PackageManagerService(以下简称 PMS)是一个常用的系统服务,主要负责系统中的 Package 的管理,应用程序的安装、卸载、查询等相关功能。其相关类图如下
注:IPackageManager 在 Android Studio 中可能找不到,因为他是一个 AIDL 处理后的文件,这里附上相关的 IPackageManager.aidl 文件
分析 PMS 之前我们先来看下这玩意是在哪里启动的。
我们都知道系统启动的时候会调用 SystemServer 的 main 函数。
注释已经说明了,这个 main 函数是通过 zygote 调用的,这块的调用链涉及到了进程启动相关,此处先不多说。看到 main 创建了一个自己然后调用 run 方法。
可以看到在 run 方法中系统将服务类型按照级别分为了三大类,引导服务、内核服务、其他服务,而 PMS 的启动就在引导服务中启动。
/** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); } private void run() { // Start services. try { //系统引导服务 startBootstrapServices(); //内核服务 startCoreServices(); //其他服务 startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { traceEnd(); } } private void startBootstrapServices() { mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); //标注① mPackageManager = mSystemContext.getPackageManager(); }我们进入 PackageManagerService 的 main 方法继续追踪。
可以看到在 main 方法中也是 new 了一把自己。然后将服务添加的 ServiceManager 中进行管理。到这,PMS 服务就启动完成了。
public class PackageManagerService extends IPackageManager.Stub implements PackageSender { public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); m.enableSystemUserPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); ServiceManager.addService("package_native", pmn); return m; } }这里在额外看一下 PackageManager 的创建。上面 标注① 出获取了 PackageManager ,我们就以此为入口看下。mSystemContext 为 Content 的一个实现类,可以直接搜 ContextImpl。
可以看到和上面的类图完美的对应上了,这里拿到系统提供的 PM,然后创建一个 ApplicationPackageManager 持有这个 pm 去和系统服务进行交互。
class ContextImpl extends Context { @Override public PackageManager getPackageManager() { if (mPackageManager != null) { return mPackageManager; } IPackageManager pm = ActivityThread.getPackageManager(); if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; } }注:Android 系统启动慢的原因就是在启动 PMS 的时候,需要执行扫描文件夹、处理权限、安装系统应用(文件的解压与copy)等比较耗时的操作。
我们下载的安装包都是一个 .apk 文件,当我们点击该文件的时候,会启动系统的一个安装 apk 的应用,该应用是系统应用,在系统启动时就已经安装成功了。这里附上 PackageInstaller.apk 源码
首先这个 Intent 会启动 InstallStart ,在这里做一些校验后就跳转到 PackageInstallerActivity 进行确认安装后,进入 InstallInstalling 界面进行安装。
可以看到在 AndroidManifest.xml 中对外暴露了 InstallStart。
<activity android:name=".InstallStart" android:exported="true" android:excludeFromRecents="true"> <intent-filter android:priority="1"> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.INSTALL_PACKAGE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="content" /> <data android:mimeType="application/vnd.android.package-archive" /> </intent-filter> <intent-filter android:priority="1"> <action android:name="android.intent.action.INSTALL_PACKAGE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="package" /> <data android:scheme="content" /> </intent-filter> <intent-filter android:priority="1"> <action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>安装界面调用流程
public class InstallStart extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ...... Intent nextActivity = new Intent(intent); ...... nextActivity.setClass(this, PackageInstallerActivity.class); ...... if (nextActivity != null) { startActivity(nextActivity); } finish(); } } public class PackageInstallerActivity extends OverlayTouchActivity implements OnClickListener { public void onClick(View v) { if (v == mOk) { if (mOk.isEnabled()) { if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); } 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); } finish(); } } private void startInstall() { // Start subactivity to actually install the application Intent newIntent = new Intent(); ...... newIntent.setClass(this, InstallInstalling.class); ...... startActivity(newIntent); finish(); } } public class InstallInstalling extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.installFlags = PackageManager.INSTALL_FULL_APP; ...... try { //标注② mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } }上面标注②中获取了 PackageInstaller 执行真正的安装
public class ApplicationPackageManager extends PackageManager { @Override public PackageInstaller getPackageInstaller() { synchronized (mLock) { if (mInstaller == null) { try { mInstaller = new PackageInstaller(mPM.getPackageInstaller(), mContext.getPackageName(), mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return mInstaller; } } } public class PackageInstaller { //标注③ private final IPackageInstaller mInstaller; public int createSession(@NonNull SessionParams params) throws IOException { try { final String installerPackage; if (params.installerPackageName == null) { installerPackage = mInstallerPackageName; } else { installerPackage = params.installerPackageName; } return mInstaller.createSession(params, installerPackage, mUserId); } catch (RuntimeException e) { ExceptionUtils.maybeUnwrapIOException(e); throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }上面标注③ 中的 IPackageInstaller 为 PackageInstallerService 的 Binder 对象,看到这里是不发现,系统服务将 Binder 通信用的是淋漓尽致啊。
这里安装完成后通过 Binder 和 Handler 进行回调。
public class PackageInstallerService extends IPackageInstaller.Stub { @Override public int createSession(SessionParams params, String installerPackageName, int userId) { try { return createSessionInternal(params, installerPackageName, userId); } catch (IOException e) { throw ExceptionUtils.wrap(e); } } private int createSessionInternal(SessionParams params, String installerPackageName, int userId) throws IOException { final int callingUid = Binder.getCallingUid(); mPermissionManager.enforceCrossUserPermission( callingUid, userId, true, true, "createSession"); if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { throw new SecurityException("User restriction prevents installing"); } if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) { params.installFlags |= PackageManager.INSTALL_FROM_ADB; } else { // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the // caller. if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) { mAppOps.checkPackage(callingUid, installerPackageName); } params.installFlags &= ~PackageManager.INSTALL_FROM_ADB; params.installFlags &= ~PackageManager.INSTALL_ALL_USERS; params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0 && !mPm.isCallerVerifier(callingUid)) { params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD; } } // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 && mContext.checkCallingOrSelfPermission(Manifest.permission .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) { throw new SecurityException("You need the " + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission " + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag"); } if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0 || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { throw new IllegalArgumentException( "New installs into ASEC containers no longer supported"); } // Defensively resize giant app icons if (params.appIcon != null) { final ActivityManager am = (ActivityManager) mContext.getSystemService( Context.ACTIVITY_SERVICE); final int iconSize = am.getLauncherLargeIconSize(); if ((params.appIcon.getWidth() > iconSize * 2) || (params.appIcon.getHeight() > iconSize * 2)) { params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize, true); } } switch (params.mode) { case SessionParams.MODE_FULL_INSTALL: case SessionParams.MODE_INHERIT_EXISTING: break; default: throw new IllegalArgumentException("Invalid install mode: " + params.mode); } // If caller requested explicit location, sanity check it, otherwise // resolve the best internal or adopted location. if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { if (!PackageHelper.fitsOnInternal(mContext, params)) { throw new IOException("No suitable internal storage available"); } } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) { if (!PackageHelper.fitsOnExternal(mContext, params)) { throw new IOException("No suitable external storage available"); } } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != 0) { // For now, installs to adopted media are treated as internal from // an install flag point-of-view. params.setInstallFlagsInternal(); } else { // For now, installs to adopted media are treated as internal from // an install flag point-of-view. params.setInstallFlagsInternal(); // Resolve best location for install, based on combination of // requested install flags, delta size, and manifest settings. final long ident = Binder.clearCallingIdentity(); try { params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params); } finally { Binder.restoreCallingIdentity(ident); } } final int sessionId; final PackageInstallerSession session; synchronized (mSessions) { // Sanity check that installer isn't going crazy final int activeCount = getSessionCount(mSessions, callingUid); if (activeCount >= MAX_ACTIVE_SESSIONS) { throw new IllegalStateException( "Too many active sessions for UID " + callingUid); } final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid); if (historicalCount >= MAX_HISTORICAL_SESSIONS) { throw new IllegalStateException( "Too many historical sessions for UID " + callingUid); } sessionId = allocateSessionIdLocked(); } final long createdMillis = System.currentTimeMillis(); // We're staging to exactly one location File stageDir = null; String stageCid = null; if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { final boolean isInstant = (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant); } else { stageCid = buildExternalStageCid(sessionId); } session = new PackageInstallerSession(mInternalCallback, mContext, mPm, mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false, false); synchronized (mSessions) { mSessions.put(sessionId, session); } mCallbacks.notifySessionCreated(session.sessionId, session.userId); writeSessionsAsync(); return sessionId; } }上面说的有界面安装是正常的安装方式,可以让用户感知的。然而还有一种比较流氓的方式,就是静默安装。用户无感知,这个应用就被安装成功了。
这种方式就是通过 adb 命令进行安装 adb install
这个命令我们可以在 commandline.cpp 中找到。可以看到通过命令匹配 执行 install_app 函数。与之相应的还有 adb uninstall 命令
int adb_commandline(int argc, const char** argv) { ...... else if (!strcmp(argv[0], "install")) { if (argc < 2) return syntax_error("install requires an argument"); if (_use_legacy_install()) { return install_app_legacy(argc, argv); } return install_app(argc, argv); } ...... else if (!strcmp(argv[0], "uninstall")) { if (argc < 2) return syntax_error("uninstall requires an argument"); if (_use_legacy_install()) { return uninstall_app_legacy(argc, argv); } return uninstall_app(argc, argv); } ...... } static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) { ...... result = pm_command(transport, serial, argc, argv); ...... return result; } static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) { std::string cmd = "pm"; while (argc-- > 0) { cmd += " " + escape_arg(*argv++); } return send_shell_command(transport, serial, cmd, false); }顺着调用栈走下去发现最终执行了 pm 命令。而这个命令会执行一个 pm.jar 文件,该 jar 包是通过 Pm.java 打包而成。
命令执行后会调用 Pm 的 main 函数。顺着调用往下走,最终发现还是调用了 PackageInstallerService 的 createSession 函数。殊途同归,和有界面安装走入相同的流程了。
public final class Pm { public static void main(String[] args) { int exitCode = 1; try { exitCode = new Pm().run(args); } 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); } public int run(String[] args) throws RemoteException { boolean validCommand = false; if (args.length < 1) { return showUsage(); } mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE)); mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE)); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { System.err.println(PM_NOT_RUNNING_ERR); return 1; } mInstaller = mPm.getPackageInstaller(); ...... if ("install".equals(op)) { return runInstall(); } ...... if ("uninstall".equals(op)) { return runUninstall(); } ...... } private int runInstall() throws RemoteException { ...... final int sessionId = doCreateSession(params.sessionParams, params.installerPackageName, params.userId); ...... } private int doCreateSession(SessionParams params, String installerPackageName, int userId) throws RemoteException { userId = translateUserId(userId, "runInstallCreate"); if (userId == UserHandle.USER_ALL) { userId = UserHandle.USER_SYSTEM; params.installFlags |= PackageManager.INSTALL_ALL_USERS; } final int sessionId = mInstaller.createSession(params, installerPackageName, userId); return sessionId; } }至此对于 PMS 的启动,和 APK 文件的两种安装方式我们都分析完了,下面对结合两种安装方式总结一下
对于 Android 系统安装 APK 应用,就是将 APK 文件解压,把相应的文件 copy 到相应的目录中即可。
data/app/package_name 安装时将 apk 文件复制到此目录,可以将文件取出并安装data/data/package_name 开辟存放应用程序的文件数据的文件夹,包括我们的 so 库、缓存文件等data/dalvik-cache 将 apk 解压出的 dex 文件复制到此目录