Andorid Framework之PKMS

362 阅读5分钟

PKMS

源代码基于android11

PKMS定义

它是android系统中核心服务之一,负责管理应用程序,其中应用程序的安装、卸载、信息查询等工作均是它来完成。

它工作的大致流程是:android系统在开机时会启动PKMS,PKMS服务扫描特定的目录,寻找apk压缩包,解析获取安装信息,然后完成程序的安装。

PKMS启动流程

  • SystemServer -> main();

  • SystemServer -> tartBootstrapServices();启动系统引导服务

  • PackageManagerService -> main();在main中做了如下事情。

    • 创建PKMS -> 进入构造器
    • 创建PackageHandler [line-2958]处理Package相关信息,效验、安装、卸载等。
    • scanDirTracedLI [line-3098] 扫描磁盘目录下apk文件
       //main方法执行完之后,将pkms服务添加到SM中
    
       ServiceManager.addService("package", m);
    
  • SystemServer -> startOtherServices();

  • PackageManagerService -> updatePackagesIfNeeded() 完成dex优化

  • PackageManagerService -> performFstrimIfNeeded() 磁盘管理功能。

  • PackageManagerService -> systemReady(); pkms已经完成启动,并准备就绪。

PKMS构造中代码分析

在PKMS的构造器中大概有一千多行代码,主要找重点。 其中重要阶段点如下(根据EventLog来区分):

  1. BOOT_PROGRESS_PMS_START -->PMS启动
  2. BOOT_PROGRESS_PMS_SYSTEM_SCAN_START -->扫描系统System目录
  3. BOOT_PROGRESS_PMS_DATA_SCAN_START -->扫描系统Data目录
  4. BOOT_PROGRESS_PMS_SCAN_END --> 扫描结束
  5. BOOT_PROGRESS_PMS_READY --> PMS准备就绪

下面具体走代码来分析。

PKMS构造第一阶段:BOOT_PROGRESS_PMS_START

第一阶段大致做了如下工作:

  • 构造DisplayMetrics,保存分辨率等相关信息

  • 创建Installer对象

  • 创建PermissionManager权限管理类

  • 创建Setting类,保存安装包信息。主要涉及data/system目录的packages.xml、package-backup、package.list、packages-stopped.xml、packages-stopped-backup.xml文件

  • 创建PackageManager的handler线程,循环处理外部安装等相关信息。

      mMetrics = new DisplayMetrics();
      mInstaller = injector.getInstaller();
      mPermissionManager = injector.getPermissionManagerServiceInternal();
      mSettings = injector.getSettings();
          
      ·······   
      synchronized (mLock) {
          mHandlerThread = new ServiceThread(TAG,
                  Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
          mHandlerThread.start();
          mHandler = new PackageHandler(mHandlerThread.getLooper());
          Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
              ·······
      }
    

PKMS构造第二阶段:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START

此阶段做了如下工作:

  • 从init.rc中获取系统环境变量BOOTCLASSPATH和SYSTEMSERVERCLASSPATH;(通过adb shell --> export 可以查看android系统所有环境变量)

      EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
              startTime);
    
      final String bootClassPath = System.getenv("BOOTCLASSPATH");
      final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
    
  • 对旧版本升级的情况,将安装时获取权限变更为运行时申请权限

  • 扫码system、vendor、product、odm、oem 等目录下的priv-app、app、overlay 包。

      // Collect vendor/product/system_ext overlay packages. (Do this before scanning
      // any apps.)
      // For security and version matching reason, only consider overlay packages if they
      // reside in the right directory.
      for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
          final ScanPartition partition = mDirsToScanAsSystem.get(i);
          if (partition.getOverlayFolder() == null) {
              continue;
          }
          scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
                  systemScanFlags | partition.scanFlag, 0,
                  packageParser, executorService);
      }
      
      scanDirTracedLI(frameworkDir, systemParseFlags,
              systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
              packageParser, executorService);
    
      for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
          final ScanPartition partition = mDirsToScanAsSystem.get(i);
          if (partition.getPrivAppFolder() != null) {
              scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
                      systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                      packageParser, executorService);
          }
          scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
                  systemScanFlags | partition.scanFlag, 0,
                  packageParser, executorService);
      }
    

PKMS构造第三阶段:BOOT_PROGRESS_PMS_DATA_SCAN_START

在扫描完system目录之后,系统还需要扫描data目录,及时更新,去除不必要的数据。

    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
            SystemClock.uptimeMillis());
    scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
            packageParser, executorService);

其中scanDirTracedLI就是关键的扫描方法,而mAppInstallDir变量值为data目录:

/** Directory where installed applications are stored */
private static final File sAppInstallDir =
        new File(Environment.getDataDirectory(), "app");

PKMS构造第四阶段:BOOT_PROGRESS_PMS_SCAN_END

在扫描完成之后,大致做了如下工作

  • SDK变化之后,更新权限[line-3428]

      final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
      if (sdkUpdated) {
          Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                  + mSdkVersion + "; regranting permissions for internal storage");
      }
      mPermissionManager.updateAllPermissions(
              StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated);
      ver.sdkVersion = mSdkVersion;
    
      
    
  • OTA升级后第一次启动清楚不必要的缓存数据[line-3501]

      if (mIsUpgrade && !mOnlyCore) {
          Slog.i(TAG, "Build fingerprint changed; clearing code caches");
          for (int i = 0; i < mSettings.mPackages.size(); i++) {
              final PackageSetting ps = mSettings.mPackages.valueAt(i);
              if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                  // No apps are running this early, so no need to freeze
                  clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                          FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
                                  | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
                                  | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
              }
          }
          ver.fingerprint = Build.FINGERPRINT;
      }
    
  • 权限等默认项更新完毕之后,清理相关数据

      // clear only after permissions and other defaults have been updated
      mPromoteSystemApps = false;
    
  • 更新Package.xml文件。

      mSettings.writeLPr();
    

PKMS构造第五阶段:BOOT_PROGRESS_PMS_READY

第五阶段是GC垃圾回收和其他一些细节。

 //得到特权控制包   
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
···
//内存回收
Runtime.getRuntime().gc();

解析APK流程

解析的流程我们需要从PKMS中的 scanDirTracedLI 开始。

  • PackageManagerService -> scanDirTracedLI()

  • PackageManagerService -> scanDirLI()

  • ParallelPackageParser -> submit()

  • ParallelPackageParser -> parsePackage()

  • PackageParser2 -> parsePackage();

     android11之前是PackageParser,而在android11开始,解析apk相关的工作都是从PackageParser2开始。不过PackageParser中的相关代码并没有删除。
     
    

image.png

image.png 如果有缓存的解析文件,会直接return。

  • ParsingPackageUtils -> parsePackage()

      //分别解析文件夹和文件,android11走的是文件夹,最后会走到parseBaseApk()方法中。
      public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
              int flags)
              throws PackageParserException {
          if (packageFile.isDirectory()) {
              return parseClusterPackage(input, packageFile, flags);
          } else {
              return parseMonolithicPackage(input, packageFile, flags);
          }
      }
    
  • ParsingPackageUtils -> parseClusterPackage()

  • ApkLiteParseUtils -> parseClusterPackageLite();返回PackageParser.PackageLite对象。

  • ApkLiteParseUtils -> parseApkLite();

  • ApkLiteParseUtils -> parseApkLiteInner();

      //打开清单文件。
      parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME);
      
       //ANDROID_MANIFEST_FILENAME变量值
      /** File name in an APK for the Android manifest. */
      public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
    
  • ApkLiteParseUtils -> parseApkLite(); 对清单文件轻度解析,只解析了如versionCode、targetSdkVersion、CoreApp等外层字段

image.png

ApkLiteParseUtils执行完,ParsingPackageUtils得到了PackageLite对象后继续往下走。

  • ParsingPackageUtils -> parseBaseApk()
  • ParsingPackageUtils -> parseBaseApkTags()
  • ParsingPackageUtils -> parseBaseApplication()

image.png 进入到parseBaseApplication中后,就开始全面解析清单文件了。

image.png

image.png

经常见到的activity、receiver、service、contentprovide等都在此处解析。

解析完成将所有信息保存在ParsingPackage中返回,最后到PackageParser2中进行缓存。

image.png

AndroidManifast.xml解析流程的时序图

image.png

apk安装流程

做系统开发,直接push到系统目录,然后机器重启就可以了。

做应用层开发,基本都是使用的adb install 安装。

我们直接查看adb install的代码流程。

在PKMS中,onShellCommand()方法就是接收adb命令的。

  • adb install xxx.apk

  • PackageManagerService -> onShellCommand();

  • PackageManagerShellCommand -> exec() -> onCommand() -> runInstall() -> doRunInstall() 在doRunInstall方法中,有两个重要的地方。

//创建Session
final int sessionId = doCreateSession(params.sessionParams,
       params.installerPackageName, params.userId);
//创建一个临时的apk,把原来的apk保存到刚刚创建的临时apk中。
if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
        != PackageInstaller.STATUS_SUCCESS) {
    return 1;
}
private int doWriteSplits(int sessionId, ArrayList<String> splitPaths, long sessionSizeBytes,
        boolean isApex) throws RemoteException {
    final boolean multipleSplits = splitPaths.size() > 1;
    for (String splitPath : splitPaths) {
        String splitName = multipleSplits ? new File(splitPath).getName()
                : "base." + (isApex ? "apex" : "apk");

        if (doWriteSplit(sessionId, splitPath, sessionSizeBytes, splitName,
                false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
            return 1;
        }
    }
    return 0;
}
  • PackageInstallerService -> createSession(); 创建好session后,继续往下执行。

  • PackageManagerShellCommand -> doWriteSplits();

  • PackageManagerShellCommand -> doCommitSession();

  • PackageInstaller.Session -> commit();

  • PackageInstallerSession -> commit(); -> dispathStreamValidataAndCommit();

      private void dispatchStreamValidateAndCommit() {
         //发送消息 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
      }
      
    
  • PackageInstallerSession -> handleStreamValidateAndCommit()

      mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
    
  • PackageInstallerSession -> handleInstall() -> installNonStagedLocked()

  • PackageManagerService -> installStage();回调到了PKMS中。

      void installStage(ActiveInstallSession activeInstallSession) {
          if (DEBUG_INSTANT) {
              if ((activeInstallSession.getSessionParams().installFlags
                      & PackageManager.INSTALL_INSTANT_APP) != 0) {
                  Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
              }
          }
          final Message msg = mHandler.obtainMessage(INIT_COPY);
          final InstallParams params = new InstallParams(activeInstallSession);
          params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
          msg.obj = params;
    
          Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
                  System.identityHashCode(msg.obj));
          Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                  System.identityHashCode(msg.obj));
    
          mHandler.sendMessage(msg);
      }
    
  • PackageManagerService -> mHandler.obtainMessage(INIT_COPY);

  • HandlerParams -> startCopy()

      final void startCopy() {
          if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
          handleStartCopy();
          handleReturnCode();
      }
    
  • PackageManagerService.InstallParams -> handleStartCopy()

  • PackageManagerService.InstallParams -> handleReturnCode()

  • PackageManagerService -> processPendingInstall()

  • PackageManagerService -> processInstallRequestsAsync()

  • PackageManagerService -> installPackagesTracedLI();

  • PackageManagerService -> installPackagesLI();走apk解析流程

    • PackageInstallerService -> preparePackageLI()
    • PackageParser2 -> parsePackage() 解析AndroidManifast.xml文件。
    • PackageInstallerService -> scanPackageTracedLI();
    • PackageInstallerService -> scanPackageNewLI();
    • PackageInstallerService -> commitPackagesLocked()
    • PackageInstallerService -> updateSettingsLI

installPackagesLI 继续往下执行

  • PackageManagerService -> scanPackageTracedLI();
  • PackageManagerService -> scanPackageNewLI();

回到PackageManagerService的processInstallRequestsAsync()方法继续往下执行

  • PackageManagerService -> restoreAndPostInstall()

  • PackageManagerService -> performRollbackManagerRestore

  • RollbackManagerServiceImpl -> snapshotAndRestoreUserData();

  • PackageManagerService -> finishPackageInstall()

      @Override
      public void finishPackageInstall(int token, boolean didLaunch) {
          enforceSystemOrRoot("Only the system is allowed to finish installs");
    
          if (DEBUG_INSTALL) {
              Slog.v(TAG, "BM finishing package install for " + token);
          }
          Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
    
          final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0);
          mHandler.sendMessage(msg);
      }
    
  • 发送POST_INSTALL消息。

  • PackageManagerService -> handlePackagePostInstall();在这个方法中发送一系列广播,通知其他模块,完成了 apk的安装。

image.png

APK安装时序图

image.png

总结

pkms是android中非常重要的一个服务,管理所有的安装包,对程序的安装、卸载、权限控制等都由它来进行操作。

目前只跟了PKMS的启动流程、清单解析流程以及apk安装流程,后期有时间会跟一下其他细节分支代码。

最后

本文只做学习记录,如有问题,感谢指出。

参考文章:

juejin.cn/post/694129… blog.csdn.net/Bill_xiao/a…