【android11】静默安装和静默卸载

修改记录
1.安装器

//Installer.java
package com.kte.interfacesettings.service;

import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.content.pm.IPackageInstallerCallback;
import java.io.File;
import android.os.RemoteException;
import java.io.FileInputStream;
import java.io.OutputStream;
import android.app.PendingIntent;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageParser;
import android.content.pm.IPackageInstaller;
import android.os.ServiceManager;
import com.android.internal.content.PackageHelper;
import android.os.UserHandle;
import android.app.ActivityManager;
import android.os.Binder;
import android.content.pm.IPackageManager;

public class Installer {
	private static String TAG = "install";

	private Installer() {
	}

	public static void silentInstallApk(Context context, String apkFilePath, int userId, boolean openWhenInstalled) {
		Log.d(TAG, "[Installer] silentInstallApk...path=" + apkFilePath);
		File apkFile = new File(apkFilePath);
		IPackageManager mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
		try {
			final IPackageInstaller packageInstaller = mPm.getPackageInstaller();
			packageInstaller.registerCallback(new IPackageInstallerCallback.Stub() {
				String pkgname = null;

				@Override
				public void onSessionProgressChanged(int sessionId, float progress) throws RemoteException {
					Log.d(TAG, "[Installer] silentInstallApk...onProgressChanged-> " + sessionId);
				}

				@Override
				public void onSessionFinished(int sessionId, boolean success) throws RemoteException {
					Log.d(TAG, "[Installer] silentInstallApk...Silent Install session " + sessionId + " Success=" + success + ",,pkgName=" + pkgname);
					if (success && openWhenInstalled) { 
						Intent intent = context.getPackageManager().getLaunchIntentForPackage(pkgname);
						context.startActivity(intent);
					} 
				}

				@Override
				public void onSessionCreated(int sessionId) throws RemoteException {
					SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
					pkgname = sessionInfo.getAppPackageName();
					Log.d(TAG, "[Installer] silentInstallApk...Install Start sessionId-> " + sessionId + ",,pkgname=" + pkgname);
				}

				@Override
				public void onSessionBadgingChanged(int sessionId) throws RemoteException {
					Log.d(TAG, "[Installer] silentInstallApk...onBadgingChanged-> " + sessionId);
				}

				@Override
				public void onSessionActiveChanged(int sessionId, boolean active) throws RemoteException {
					Log.d(TAG, "[Installer] silentInstallApk...onActiveChanged-> " + sessionId);
				}
			}, userId);
			PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
					PackageInstaller.SessionParams.MODE_FULL_INSTALL);
			try {
				PackageParser.PackageLite pkg = PackageParser.parsePackageLite(apkFile, 0);
				sessionParams.setAppPackageName(pkg.packageName);
				sessionParams.setInstallLocation(pkg.installLocation);
				sessionParams.setSize(PackageHelper.calculateInstalledSize(pkg, sessionParams.abiOverride));
			} catch (PackageParser.PackageParserException e) {
				Log.e(TAG, "[Installer] silentInstallApk...Cannot parse package " + apkFile, e);
				sessionParams.setSize(apkFile.length());
			} catch (IOException e) {
				Log.e(TAG, "[Installer] silentInstallApk...Cannot calculate installed size " + apkFile, e);
				sessionParams.setSize(apkFile.length());
			}

			int sessionId = -1;
			final int translatedUserId = translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");
			sessionId = packageInstaller.createSession(sessionParams, context.getApplicationContext().getPackageName(),
					translatedUserId);
			Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk  sessionId=" + sessionId);
			if (sessionId != -1) {
				boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkFilePath);
				Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk  copySuccess=" + copySuccess);
				if (copySuccess) {
					Log.d(TAG, "[Installer] silentInstallApk...silentInstallApk  copySuccess...111...");
					execInstallCommand(context, packageInstaller, sessionId);
				}
			}
		} catch (RemoteException e1) {
			Log.e(TAG, "[Installer] silentInstallApk...silentInstallApk  e1=" + e1);
			e1.printStackTrace();
		}
	}

	private static boolean copyInstallFile(IPackageInstaller packageInstaller, int sessionId, String apkFilePath) {
		InputStream in = null;
		OutputStream out = null;
		PackageInstaller.Session session = null;
		boolean success = false;
		try {
			File apkFile = new File(apkFilePath);
			session = new PackageInstaller.Session(packageInstaller.openSession(sessionId));
			out = session.openWrite("base.apk", 0, apkFile.length());
			in = new FileInputStream(apkFile);
			int total = 0, c;
			byte[] buffer = new byte[65536];
			while ((c = in.read(buffer)) != -1) {
				total += c;
				out.write(buffer, 0, c);
			}
			session.fsync(out);
			Log.i(TAG, "[Installer] copyInstallFile...streamed " + total + " bytes");
			success = true;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
				in.close();
				session.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return success;
	}

	private static int translateUserId(int userId, int allUserId, String logContext) {
		final boolean allowAll = (allUserId != UserHandle.USER_NULL);
		final int translatedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
				userId, allowAll, true, logContext, "pm command");
		return translatedUserId == UserHandle.USER_ALL ? allUserId : translatedUserId;
	}

	private static void execInstallCommand(Context context, IPackageInstaller packageInstaller, int sessionId) {
		PackageInstaller.Session session = null;
		try {
			Log.d(TAG, "[Installer] execInstallCommand......");
			session = new PackageInstaller.Session(packageInstaller.openSession(sessionId));
			Intent intent = new Intent("com.android.my_install_apk_broadcat");
			intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FROM_SHELL | 0x01000000);
			PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
			session.commit(pendingIntent.getIntentSender());
			Log.i(TAG, "[Installer] execInstallCommand...begin session");
		} catch (RemoteException e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
	}
}

2.解决正常发广播的问题

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
            String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
        if ((intent.getFlags() & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
            // Don't yell about broadcasts sent via shell
            return;
        }

        final String action = intent.getAction();
        if (isProtectedBroadcast
				|| "com.android.my_install_apk_broadcat".equals(action) //添加这个判断
                || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MEDIA_BUTTON.equals(action)
                || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MASTER_CLEAR.equals(action)
                || Intent.ACTION_FACTORY_RESET.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
                || TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
                || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
                || AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
                || AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION.equals(action)) {
            // Broadcast is either protected, or it's a public action that
            // we've relaxed, so it's fine for system internals to send.
            return;
        }
        ......
}

3.调用安装器

//FuncTools.java
@SuppressWarnings("deprecation")
public void directInstall(String path, boolean install, final boolean openWhenInstalled) {
	try {
		if (!TextUtils.isEmpty(path)) {
			IPackageManager mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
			if (install) {  //静默安装
				Installer.silentInstallApk(mContext,path,UserHandle.myUserId(),openWhenInstalled);
			} else {     //静默卸载
				IPackageDeleteObserver observer = new IPackageDeleteObserver.Stub() {
					@Override
					public void packageDeleted(String packageName, int returnCode) throws RemoteException {
						android.util.Log.d(TAG, "directInstall...packageDeleted...");
					}
				};
				mPm.deletePackageAsUser(path, PackageManager.VERSION_CODE_HIGHEST, observer, UserHandle.myUserId(),
						PackageManager.DELETE_ALL_USERS);
			}
		}
			 
	} catch (Exception e) {
		e.printStackTrace();
		android.util.Log.e(TAG, "directInstall error:path=" + path + ",,install=" + install + ",,open=" + openWhenInstalled+",e="+e);
	}
}

4.广播接收安装信息

//MainActivity.java
@Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     //注册动态广播
     IntentFilter filter = new IntentFilter();
     filter.addAction("com.android.my_install_apk_broadcat");
     registerReceiver(myInstallReceiver, filter);
 }

//广播监听
BroadcastReceiver myInstallReceiver = new BroadcastReceiver() {
     @Override
     public void onReceive(Context context, Intent intent) {
         Log.d(TAG,"[MainActivity] onReceive...action="+intent.getAction());
         if ("com.android.my_install_apk_broadcat".equals(intent.getAction())) {
             String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
             String statusMsg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
             int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);
             Log.i(TAG, "install_apk_broadcat,,,pkgName=" + pkgName + ",,statusMsg=" + statusMsg + ",,status="
                     + status);
         }
     }
 };

你可能感兴趣的:(Android,android,java,android,studio)