一、PackageManagerService简称PMS:PackageManagerService是Android系统中核心的
服务之一,负责应用程序的查询,卸载和应用信息查询,相当于应用程序的大管家。
try { //调用系统的方法,获取应用程序信息 context.getPackageManager().getPackageInfo(null, 0); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); }
1、首先是在抽象类PackageManager中定义了抽象方法getPackageInfo()
public abstract PackageInfo getPackageInfo(@NonNull String packageName, @PackageInfoFlags int flags) throws NameNotFoundException;
2、类ApplicationPackageManager继承PackageManager类,重写了getPackageInfo()方法
@Override public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException { return getPackageInfoAsUser(packageName, flags, mContext.getUserId()); }
实际调用了getPackageInfoAsUser()方法
@Override public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) throws NameNotFoundException { try { PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId); if (pi != null) { return pi; } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } throw new NameNotFoundException(packageName); }
mPM是系统中写的AIDL文件,通过mPM.getPackageInfo(),调用到代理对象Proxy类中重写的getPackageInfo()方法,代理对象又调用到PackageManagerService中的getPackageInfo()方法。
二、APK安装原理
1.APK安装的两种方式
1.静默安装,又叫无界面的安装,从各大手机厂商应用商店下载的APK,便是无界面的安装。
2.有界面的安装,从三方托管平台下载一个APK包,需要一步一步来操作的。
下面分析有界面的安装
1、点击安装后,会跳转到系统提供的PackageInstallerActivity和其对应的布局
install_start.xml.
2、之后通过PackageUtil类获取APK包里面的信息
PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
3、如果用户点击安装按钮进行安装,或者取消,两种情况。
public void onClick(View v) { if (v == mOk) { //点击安装 if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); clearCachedApkIfNeededAndFinish(); } else { startInstall(); //跳转到一个新的页面,显示正在安装 } } else { mScrollView.pageScroll(View.FOCUS_DOWN); } } else if (v == mCancel) { //点击取消 // Cancel and finish setResult(RESULT_CANCELED); if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } clearCachedApkIfNeededAndFinish(); } }
4、正在安装中的Activity类名为:InstallAppProgress 继承Activity。
以上是有界面的安装方式的简单分析。
下面分析无界面的安装方式:
1、没有界面的安装方式,最开始是从C代码开始执行的。
首先通过adb install 输入包名后,一敲回车,会执行到commandline.c文件下的,adb_commandline()方法。
2.最终会调用到install_app()方法
char* apk_file = argv[last_apk]; char apk_dest[PATH_MAX]; //APK安装路径 snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);//把APK,push到手机存储里面。 if (err) { goto cleanup_apk; } else { argv[last_apk] = apk_dest; /* destination name, not source location */ } pm_command(transport, serial, argc, argv); //这个方法是为了执行shell:pm以命名的方式去安装
3、pm_command()方法如下
static int pm_command(transport_type transport, char* serial, int argc, char** argv) { char buf[4096]; snprintf(buf, sizeof(buf), "shell:pm"); //借助pm的脚本文件,实现安装,通过pm命名的方式实现安装操作 while(argc-- > 0) { char *quoted = escape_arg(*argv++); strncat(buf, " ", sizeof(buf) - 1); strncat(buf, quoted, sizeof(buf) - 1); free(quoted); } send_shellcommand(transport, serial, buf); return 0; }
4、pm脚本文件
# Script to start "pm" on the device, which has a very rudimentary # shell. # base=/system export CLASSPATH=$base/framework/pm.jar //重点是找到pm.jar exec app_process $base/bin com.android.commands.pm.Pm "$@"
5、Android源码frameworks/base/cmds/pm/src/com/android/commands/pm.java 源码中有一个main方法如下
public static void main(String[] args) { int exitCode = 1; try { exitCode = new Pm().run(args); //重点关注run()方法 } catch (Exception e) { Log.e(TAG, "Error", e); System.err.println("Error: " + e); if (e instanceof RemoteException) { System.err.println(PM_NOT_RUNNING_ERR); } } System.exit(exitCode); }
6、run方法代码如下
public int run(String[] args) throws IOException, RemoteException { boolean validCommand = false; if (args.length < 1) { return showUsage(); } mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { System.err.println(PM_NOT_RUNNING_ERR); return 1; } mInstaller = mPm.getPackageInstaller(); mArgs = args; String op = args[0]; mNextArg = 1; if ("list".equals(op)) { return runList(); } if ("path".equals(op)) { return runPath(); } if ("dump".equals(op)) { return runDump(); } if ("install".equals(op)) { //安装 return runInstall(); } if ("install-create".equals(op)) { return runInstallCreate(); } if ("install-write".equals(op)) { return runInstallWrite(); } if ("install-commit".equals(op)) { return runInstallCommit(); } if ("install-abandon".equals(op) || "install-destroy".equals(op)) { return runInstallAbandon(); } if ("set-installer".equals(op)) { return runSetInstaller(); } if ("uninstall".equals(op)) { //卸载 return runUninstall(); } if ("clear".equals(op)) { return runClear(); } if ("enable".equals(op)) { return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); } if ("disable".equals(op)) { return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); } if ("disable-user".equals(op)) { return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); } if ("disable-until-used".equals(op)) { return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); } if ("hide".equals(op)) { return runSetHiddenSetting(true); } if ("unhide".equals(op)) { return runSetHiddenSetting(false); } if ("grant".equals(op)) { return runGrantRevokePermission(true); } if ("revoke".equals(op)) { return runGrantRevokePermission(false); } if ("set-permission-enforced".equals(op)) { return runSetPermissionEnforced(); } if ("set-install-location".equals(op)) { return runSetInstallLocation(); } if ("get-install-location".equals(op)) { return runGetInstallLocation(); } if ("trim-caches".equals(op)) { return runTrimCaches(); } if ("create-user".equals(op)) { return runCreateUser(); } if ("remove-user".equals(op)) { return runRemoveUser(); } if ("get-max-users".equals(op)) { return runGetMaxUsers(); } if ("force-dex-opt".equals(op)) { return runForceDexOpt(); } try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { validCommand = true; return runListPackages(false); } else if (args[0].equalsIgnoreCase("-lf")){ validCommand = true; return runListPackages(true); } } else if (args.length == 2) { if (args[0].equalsIgnoreCase("-p")) { validCommand = true; return displayPackageFilePath(args[1]); } } return 1; } finally { if (validCommand == false) { if (op != null) { System.err.println("Error: unknown command '" + op + "'"); } showUsage(); } } }
7、在runInstall()方法中,主要是调用了该方法
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); //实际调用的是PackageManagerService中的installPackageAsUser()方法 mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags, installerPackageName, verificationParams, abi, userId);
8、实际调用的是PackageManagerService中的installPackageAsUser()方法
/** * 1、originPath:代表应用程序文件的路径。这是一个字符串类型的参数,表示应用程序安装包的位置。 * * 2、observer:代表应用程序安装的观察者。它是IPackageInstallObserver2接口的一个实例,通过观察者模式来监听安装过程的状态和结果。 * * 3、installFlags:代表安装标志。这是一个整型参数,用于指定安装时的特定选项。例如,可以通过设置INSTALL_REPLACE_EXISTING标志来替换已存在的应用。 * * 4、installerPackageName:代表安装程序的名称。这是一个字符串类型的参数,表示执行安装的应用程序的包名。 * * 5、userId:代表要安装应用的用户ID。这是一个整型参数,用于指定要安装应用的用户。在多用户系统中,每个用户拥有自己的应用安装目录。 */ @Override public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, int userId)
9.最后通过Handler发送消息,最后执行到startCopy()方法
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); if (++mRetries > MAX_RETRIES) { //安装次数大于4次,安装失败 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode(); return res; }
9、最后执行安装操作的方法handleReturnCode()
@Override void handleReturnCode() { if (mObserver != null) { try { mObserver.onGetStatsCompleted(mStats, mSuccess); } catch (RemoteException e) { Slog.i(TAG, "Observer no longer exists."); } } }
APK无界面安装流程图
APK安装原理如下: