Android10.0 PKMS 源码解读(二)

三部曲 - APK的扫描:
同学们注意:PKMS的构造函数中调用了 scanDirTracedLI方法 来扫描某个目录的apk文件。
同学们注意:Android10.0 和 其他低版本扫描的路径是不一样的:Android 10.0中,PKMS主要扫描以
下路径的APK信息:

/vendor/overlay 系统的APP类别
/product/overlay 系统的APP类别
/product_services/overlay 系统的APP类别
/odm/overlay 系统的APP类别
/oem/overlay 系统的APP类别
/system/framework 系统的APP类别
/system/priv-app 系统的APP类别
/system/app 系统的APP类别
/vendor/priv-app 系统的APP类别
/vendor/app 系统的APP类别
/odm/priv-app 系统的APP类别
/odm/app 系统的APP类别
/oem/app 系统的APP类别
/oem/priv-app 系统的APP类别
/product/priv-app 系统的APP类别
/product/app 系统的APP类别
/product_services/priv-app 系统的APP类别
/product_services/app 系统的APP类别
/product_services/priv-app 系统的APP类别

APK的扫描,整体描述图:

PKMS.scanDirTracedLi:首先加入了一些systtrace的日志追踪,然后调用scanDirLI()进行分析

private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
long currentTime) {
  Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" +
scanDir.getAbsolutePath() + "]");
  try {
    // 【同学们注意】会调用此 scanDirLI函数
    scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
 } finally {
    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 }
}

PKMS.scanDirLI: 使用了ParallelPackageParser的对象,ParallelPackageParser是一个队列,我们这
里手机所有系统的apk,然后从这些队列里面取出apk,再调用PackageParser 解析进行解析:

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long
currentTime) {
  final File[] files = scanDir.listFiles();
  if (ArrayUtils.isEmpty(files)) {
    Log.d(TAG, "No files in app dir " + scanDir);
    return;
 }
  if (DEBUG_PACKAGE_SCANNING) {
    Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
        + " flags=0x" + Integer.toHexString(parseFlags));
 }
  // parallelPackageParser是一个队列,收集系统 apk 文件,
  // 然后从这个队列里面一个个取出 apk ,调用 PackageParser 解析
  try (ParallelPackageParser parallelPackageParser = new
ParallelPackageParser(
      mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
      mParallelPackageParserCallback)) {
    // Submit files for parsing in parallel
    int fileCount = 0;
    for (File file : files) {
      // 是Apk文件,或者是目录
      final boolean isPackage = (isApkFile(file) || file.isDirectory())
          && !PackageInstallerService.isStageName(file.getName());
      过滤掉非 apk 文件,如果不是则跳过继续扫描
      if (!isPackage) {
        // Ignore entries which are not packages
        continue;
     }
      // 把APK信息存入parallelPackageParser中的对象mQueue,PackageParser()函数
赋给了队列中的pkg成员
      // 【同学们注意】 这里的 submit 函数 很重要,下面就会分析此函数
      parallelPackageParser.submit(file, parseFlags);
      fileCount++;
   }
    // Process results one by one
    for (; fileCount > 0; fileCount--) {
    // 从parallelPackageParser中取出队列apk的信息
      ParallelPackageParser.ParseResult parseResult =
parallelPackageParser.take();
      Throwable throwable = parseResult.throwable;
      int errorCode = PackageManager.INSTALL_SUCCEEDED;
      if (throwable == null) {
        // TODO(toddke): move lower in the scan chain
        // Static shared libraries have synthetic package names
        if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
          renameStaticSharedLibraryPackage(parseResult.pkg);
       }
        try {
          //调用 scanPackageChildLI 方法扫描一个特定的 apk 文件
          // 该类的实例代表一个 APK 文件,所以它就是和 apk 文件对应的数据结构。
          scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
              currentTime, null);
       } catch (PackageManagerException e) {
          errorCode = e.error;
          Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": "
+ e.getMessage());
       }
     } else if (throwable instanceof
PackageParser.PackageParserException) {
        PackageParser.PackageParserException e =
(PackageParser.PackageParserException)
            throwable;
        errorCode = e.error;
        Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " +
e.getMessage());
     } else {
        throw new IllegalStateException("Unexpected exception occurred
while parsing "
            + parseResult.scanFile, throwable);
     }
      // Delete invalid userdata apps
      //如果是非系统 apk 并且解析失败
      if ((scanFlags & SCAN_AS_SYSTEM) == 0 &&
          errorCode != PackageManager.INSTALL_SUCCEEDED) {
        logCriticalInfo(Log.WARN,
            "Deleting invalid package at " + parseResult.scanFile);
        // 非系统 Package 扫描失败,删除文件
        removeCodePathLI(parseResult.scanFile);
     }
   }
 }
}

ParallelPackageParser.submit :
把扫描路径中的APK等内容,放入队列mQueue,
并把parsePackage() pp 赋给ParseResult,用于后面的调用

public void submit(File scanFile, int parseFlags) {
  mService.submit(() -> {
    ParseResult pr = new ParseResult();
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" +
scanFile + "]"); // 日志打印
    try {
      PackageParser pp = new PackageParser();
      pp.setSeparateProcesses(mSeparateProcesses);
      pp.setOnlyCoreApps(mOnlyCore);
      pp.setDisplayMetrics(mMetrics);
      pp.setCacheDir(mCacheDir);
      pp.setCallback(mPackageParserCallback);
      pr.scanFile = scanFile;
      // 并把parsePackage()与pp 赋值ParseResult,用于后面的调用
      pr.pkg = parsePackage(pp, scanFile, parseFlags); // 【同学们注意】
parsePackage下面会分析
   } catch (Throwable e) {
      pr.throwable = e;
   } finally {
      Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
   }
    try {
      // 把扫描路径中的APK等内容,放入队列mQueue
      mQueue.put(pr);
   } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      // Propagate result to callers of take().
      // This is helpful to prevent main thread from getting stuck waiting
on
      // ParallelPackageParser to finish in case of interruption
      mInterruptedInThread = Thread.currentThread().getName();
   }
 });
}

通过 PackageParser.parsePackage 进行apk解析:
如果传入的packageFile是目录, 调用parseClusterPackage()解析
如果传入的packageFile是APK文件, 调用parseMonolithicPackage()解析

public Package parsePackage(File packageFile, int flags, boolean useCaches)
    throws PackageParserException {
...
  if (packageFile.isDirectory()) {
  //如果传入的packageFile是目录,调用parseClusterPackage()解析
    parsed = parseClusterPackage(packageFile, flags);
 } else {
  //如果是APK文件,就调用parseMonolithicPackage()解析
    parsed = parseMonolithicPackage(packageFile, flags);  // 【同学们注意】下面
我们分析此函数
 }
...
  return parsed;
}

PackageParser.parseMonolithicPackage(),它的作用是解析给定的APK文件,将其作为单个单块包
处理,最终调用parseBaseApk()进行解析

public Package parseMonolithicPackage(File apkFile, int flags) throws
PackageParserException {
  final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
  if (mOnlyCoreApps) {
    if (!lite.coreApp) {
      throw new
PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
          "Not a coreApp: " + apkFile);
   }
 }
  final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite,
flags);
  try {
 // 对核心应用解析 【同学们注意】 最终调用parseBaseApk()进行解析,我们下面来分析
    final Package pkg = parseBaseApk(apkFile,
assetLoader.getBaseAssetManager(), flags);
    pkg.setCodePath(apkFile.getCanonicalPath());
    pkg.setUse32bitAbi(lite.use32bitAbi);
    return pkg;
 } catch (IOException e) {
    throw new
PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
        "Failed to get path: " + apkFile, e);
 } finally {
    IoUtils.closeQuietly(assetLoader);
 }
}

PackageParser.parseBaseApk()主要是对AndroidManifest.xml进行解析,解析后所有的信息放在
Package对象中

private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
    throws PackageParserException {
  final String apkPath = apkFile.getAbsolutePath();
...
  XmlResourceParser parser = null;
...
    final int cookie = assets.findCookieForPath(apkPath);
    if (cookie == 0) {
      throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
          "Failed adding asset path: " + apkPath);
   }
    // 获得一个 XML 资源解析对象,该对象解析的是 APK 中的 AndroidManifest.xml 文件。
    parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME);
    final Resources res = new Resources(assets, mMetrics, null);
    final String[] outError = new String[1];
 
 // 再调用重载函数parseBaseApk()最终到parseBaseApkCommon(),解析
AndroidManifest.xml 后得到一个Package对象
  // 【同学们注意】解析后所有的信息放在Package对象中
    final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
 ...
    pkg.setVolumeUuid(volumeUuid);
    pkg.setApplicationVolumeUuid(volumeUuid);
    pkg.setBaseCodePath(apkPath);
    pkg.setSigningDetails(SigningDetails.UNKNOWN);
    return pkg;
...
}

parseBaseApk -----> parseBaseApkCommon , parseBaseApk省略了
PackageParser.parseBaseApkCommon 从AndroidManifest.xml中获取标签名,解析标签中的各个
item的内容,存入Package对象中
例如:获取标签 "application"、"permission"、"package"、"manifest"

private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags,
Resources res,
    XmlResourceParser parser, int flags, String[] outError) throws
XmlPullParserException,
    IOException {
 TypedArray sa = res.obtainAttributes(parser,
      com.android.internal.R.styleable.AndroidManifest);
 //拿到AndroidManifest.xml 中的sharedUserId, 一般情况下有“android.uid.system”等信息
 String str = sa.getNonConfigurationString(
      com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
  
 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
      && (type != XmlPullParser.END_TAG || parser.getDepth() >
outerDepth)) {
  //从AndroidManifest.xml中获取标签名
  String tagName = parser.getName();
  //如果读到AndroidManifest.xml中的tag是"application",执行parseBaseApplication()进
行解析
  if (tagName.equals(TAG_APPLICATION)) {
      if (foundApp) {
   ...
     }
      foundApp = true;
   
  // 解析"application"的信息,赋值给pkg
   // 【同学们注意】这里解析到的是"application" <application 包含了 四大组件,
下面分析此操作
      if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
        return null;
     }
  ...
   //如果标签是"permission"
   else if (tagName.equals(TAG_PERMISSION)) {
  //进行"permission"的解析
      if (!parsePermission(pkg, res, parser, outError)) {
        return null;
     }
  ....
  }
 }
}

上面解析AndroidManifest.xml,会得到 "application"、"overlay"、"permission"、"uses-
permission" 等信息
我们下面就针对"application"进行展开分析一下,进入 PackageParser.parseBaseApplication()函数

private boolean parseBaseApplication(Package owner, Resources res,
      XmlResourceParser parser, int flags, String[] outError)
 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
        && (type != XmlPullParser.END_TAG || parser.getDepth() >
innerDepth)) {
  // 获取"application"子标签的标签内容
  String tagName = parser.getName();
  // 如果标签是"activity"
    if (tagName.equals("activity")) { // 解析Activity的信息,把activity加入
Package对象
      Activity a = parseActivity(owner, res, parser, flags, outError,
cachedArgs, false,
          owner.baseHardwareAccelerated);
      if (a == null) {
        mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
     }
      hasActivityOrder |= (a.order != 0);
      owner.activities.add(a);
   } else if (tagName.equals("receiver")) { // 如果标签是"receiver",获取
receiver信息,加入Package对象
      Activity a = parseActivity(owner, res, parser, flags, outError,
cachedArgs, true, false);
      if (a == null) {
        mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
     }
      hasReceiverOrder |= (a.order != 0);
      owner.receivers.add(a);
   }else if (tagName.equals("service")) { // 如果标签是"service",获取service信
息,加入Package对象
      Service s = parseService(owner, res, parser, flags, outError,
cachedArgs);
      if (s == null) {
        mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
     }
      hasServiceOrder |= (s.order != 0);
      owner.services.add(s);
   }else if (tagName.equals("provider")) { // 如果标签是"provider",获取
provider信息,加入Package对象
      Provider p = parseProvider(owner, res, parser, flags, outError,
cachedArgs);
      if (p == null) {
        mParseError =
PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
     }
      owner.providers.add(p);
   }
 ...
}
}

在 PackageParser 扫描完一个 APK 后,此时系统已经根据该 APK 中 AndroidManifest.xml,创建了一
个完整的 Package 对象

APK的扫描,自我总结:
第一步:扫描APK,解析AndroidManifest.xml文件,得到清单文件各个标签内容
第二步:解析清单文件到的信息由 Package 保存。从该类的成员变量可看出,和 Android 四大组件相关
的信息分别由 activites、receivers、providers、services 保存,由于一个 APK 可声明多个组件,因此
activites 和 receivers等均声明为 ArrayList

四部曲 - APK的安装:
安装步骤一: 把Apk的信息通过IO流的形式写入到PackageInstaller.Session中
安装步骤二: 调用PackageInstaller.Session的commit方法, 把Apk的信息交给PKMS处理
安装步骤三: 进行Apk的Copy操作, 进行安装
安装的三步走, 整体描述图:

用户点击 xxx.apk 文件进行安装, 从 开始安装 到 完成安装 流程如下:

APK的安装, 整体描述图:

点击一个apk后,会弹出安装界面,点击确定按钮后,会进入PackageInstallerActivity 的 bindUi() 中
的mAlert点击事件, 弹出的安装界面底部显示的是一个diaglog,主要由bindUi构成,上面有 ”取消“ 和 ”
安装“ 两个按钮,点击安装后 调用startInstall()进行安装:

private void bindUi() {
  mAlert.setIcon(mAppSnippet.icon);
  mAlert.setTitle(mAppSnippet.label);
  mAlert.setView(R.layout.install_content_view);
  mAlert.setButton(DialogInterface.BUTTON_POSITIVE,
getString(R.string.install),
     (ignored, ignored2) -> {
        if (mOk.isEnabled()) {
          if (mSessionId != -1) {
            mInstaller.setPermissionsResult(mSessionId, true);
            finish();
         } else {
            startInstall();  // 进行APK安装 [同学们注意] 下面开始分析
startInstall 做的事情
         }
       }
     }, null);
  mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
     (ignored, ignored2) -> {
        // Cancel and finish
        setResult(RESULT_CANCELED);
        if (mSessionId != -1) {
          //如果mSessionId存在,执行setPermissionsResult()完成取消安装
          mInstaller.setPermissionsResult(mSessionId, false);
       }
        finish();
     }, null);
  setupAlert();
  mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
  mOk.setEnabled(false);
}

startInstall方法组装了一个Intent,并跳转到 InstallInstalling 这个Activity,并关闭掉当前的
PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调:

private void startInstall() {
  // Start subactivity to actually install the application
  Intent newIntent = new Intent();
  newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
      mPkgInfo.applicationInfo);
  newIntent.setData(mPackageURI);
  // 设置Intent中的class为 InstallInstalling,用来进行Activity跳转
  // class InstallInstalling extends AlertActivity [同学们注意] 下面会分析
InstallInstalling Activity
  newIntent.setClass(this, InstallInstalling.class);
  String installerPackageName = getIntent().getStringExtra(
      Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
    newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
 }
  if (mReferrerURI != null) {
    newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
 }
  if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
    newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
 }
  if (installerPackageName != null) {
    newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
        installerPackageName);
 }
  if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
    newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
 }
  newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
  if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
  startActivity(newIntent);
  finish();
}

启动 InstallInstalling,进入onCreate, 重点是看onCreate函数中的六步:

protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ApplicationInfo appInfo = getIntent()
     .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
  mPackageURI = getIntent().getData();
  if ("package".equals(mPackageURI.getScheme())) {
    try {
      getPackageManager().installExistingPackage(appInfo.packageName);
      launchSuccess();
   } catch (PackageManager.NameNotFoundException e) {
      launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
   }
 } else {
    //根据mPackageURI创建一个对应的File
    final File sourceFile = new File(mPackageURI.getPath());
    PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo,
sourceFile);
    mAlert.setIcon(as.icon);
    mAlert.setTitle(as.label);
    mAlert.setView(R.layout.install_content_view);
    mAlert.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel),
       (ignored, ignored2) -> {
          if (mInstallingTask != null) {
            mInstallingTask.cancel(true);
         }
          if (mSessionId > 0) {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
            mSessionId = 0;
         }
          setResult(RESULT_CANCELED);
          finish();
       }, null);
    setupAlert();
    requireViewById(R.id.installing).setVisibility(View.VISIBLE);
    // 第一步.如果savedInstanceState不为null,获取此前保存的mSessionId和
mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id
    if (savedInstanceState != null) {
      mSessionId = savedInstanceState.getInt(SESSION_ID);
      mInstallId = savedInstanceState.getInt(INSTALL_ID);
      // Reregister for result; might instantly call back if result was
delivered while
      // activity was destroyed
      try {
        // 第二步.根据mInstallId向InstallEventReceiver注册一个观察者,
launchFinishBasedOnResult会接收到安装事件的回调,
        //无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果
savedInstanceState为null,代码的逻辑也是类似的
        InstallEventReceiver.addObserver(this, mInstallId,
            this::launchFinishBasedOnResult);
     } catch (EventResultPersister.OutOfIdsException e) {
        // Does not happen
     }
   } else {
      // 第三步.创建SessionParams,它用来代表安装会话的参数,组装params
      PackageInstaller.SessionParams params = new
PackageInstaller.SessionParams(
          PackageInstaller.SessionParams.MODE_FULL_INSTALL);
      params.setInstallAsInstantApp(false);
    
 params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
      params.setOriginatingUri(getIntent()
         .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
    
 params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
          UID_UNKNOWN));
      params.setInstallerPackageName(getIntent().getStringExtra(
          Intent.EXTRA_INSTALLER_PACKAGE_NAME));
      params.setInstallReason(PackageManager.INSTALL_REASON_USER);
      // 第四步.根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给
SessionParams
      File file = new File(mPackageURI.getPath());
      try {
        PackageParser.PackageLite pkg =
PackageParser.parsePackageLite(file, 0);
        params.setAppPackageName(pkg.packageName);
        params.setInstallLocation(pkg.installLocation);
        params.setSize(
            PackageHelper.calculateInstalledSize(pkg, false,
params.abiOverride));
     } catch (PackageParser.PackageParserException e) {
        Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming
defaults.");
        Log.e(LOG_TAG,
            "Cannot calculate installed size " + file + ". Try only
apk size.");
        params.setSize(file.length());
     } catch (IOException e) {
        Log.e(LOG_TAG,
            "Cannot calculate installed size " + file + ". Try only
apk size.");
        params.setSize(file.length());
     }
      try {
        // 第五步.向InstallEventReceiver注册一个观察者返回一个新的mInstallId,
        //其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并
回调给EventResultPersister。
        mInstallId = InstallEventReceiver
           .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                this::launchFinishBasedOnResult);
     } catch (EventResultPersister.OutOfIdsException e) {
        launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
     }
      try {
        // 第六步.PackageInstaller的createSession方法内部会通过
IPackageInstaller与PackageInstallerService进行进程间通信,
        //最终调用的是PackageInstallerService的createSession方法来创建并返回
mSessionId
        mSessionId =
getPackageManager().getPackageInstaller().createSession(params);
     } catch (IOException e) {
        launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
null);
     }
   }
    mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
    mSessionCallback = new InstallSessionCallback();
 }
}

以上第六步是重点 PackageInstaller 的 createSession()内部会通过IPackageInstaller与
PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法
来创建并返回mSessionId
InstallInstalling.onResume方法中,调用onPostExecute()方法,将APK的信息通过IO流的形式写入
到PackageInstaller.Session中

protected void onResume() {
  super.onResume();
  // This is the first onResume in a single life of the activity
  if (mInstallingTask == null) {
    PackageInstaller installer = getPackageManager().getPackageInstaller();
    // 获取sessionInfo
    PackageInstaller.SessionInfo sessionInfo =
installer.getSessionInfo(mSessionId);
    if (sessionInfo != null && !sessionInfo.isActive()) {
      // 【同学们注意】 最终执行onPostExecute() 下面来分析
      // 创建内部类InstallingAsyncTask的对象,调用execute(),最终进入
onPostExecute()
      mInstallingTask = new InstallingAsyncTask();
      mInstallingTask.execute();
   } else {
      // we will receive a broadcast when the install is finished
      mCancelButton.setEnabled(false);
      setFinishOnTouchOutside(false);
   }
 }
}

Installinstalling.InstallingAsyncTask: 关注 第一步 和 第二步

private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
  volatile boolean isDone;
  // 第一步: doInBackground()会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到
PackageInstaller.Session中
  @Override
  protected PackageInstaller.Session doInBackground(Void... params) {
    PackageInstaller.Session session;
    try {
      session =
getPackageManager().getPackageInstaller().openSession(mSessionId);
   } catch (IOException e) {
      return null;
   }
    session.setStagingProgress(0);
    try {
      File file = new File(mPackageURI.getPath());
      try (InputStream in = new FileInputStream(file)) {
        long sizeBytes = file.length();
        try (OutputStream out = session
           .openWrite("PackageInstaller", 0, sizeBytes)) {
          byte[] buffer = new byte[1024 * 1024];
          while (true) {
            int numRead = in.read(buffer);
            if (numRead == -1) {
              session.fsync(out);
              break;
           }
           if (isCancelled()) {
              session.close();
              break;
           }
            //将APK的信息通过IO流的形式写入到PackageInstaller.Session中
            out.write(buffer, 0, numRead);
            if (sizeBytes > 0) {
              float fraction = ((float) numRead / (float)
sizeBytes);
              session.addProgress(fraction);
           }
         }
       }
     }
      return session;
   } catch (IOException | SecurityException e) {
      Log.e(LOG_TAG, "Could not write package", e);
      session.close();
      return null;
   } finally {
      synchronized (this) {
        isDone = true;
        notifyAll();
     }
   }
 }
  // 第二步:最后在onPostExecute()中 调用PackageInstaller.Session的commit方法,进行
安装
  @Override
  protected void onPostExecute(PackageInstaller.Session session) {
    if (session != null) {
      Intent broadcastIntent = new Intent(BROADCAST_ACTION);
      broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
      broadcastIntent.setPackage(getPackageName());
      broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
      PendingIntent pendingIntent = PendingIntent.getBroadcast(
          InstallInstalling.this,
          mInstallId,
          broadcastIntent,
          PendingIntent.FLAG_UPDATE_CURRENT);
      // 【同学们注意】commit 下面会分析
      // 调用PackageInstaller.Session的commit方法,进行安装
      session.commit(pendingIntent.getIntentSender());
      mCancelButton.setEnabled(false);
      setFinishOnTouchOutside(false);
   } else {
    
 getPackageManager().getPackageInstaller().abandonSession(mSessionId);
      if (!isCancelled()) {
        launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
     }
   }
 }
}

PackageInstaller的commit()

[PackageInstaller.java] commit
public void commit(@NonNull IntentSender statusReceiver) {
  try {
    // mSession的类型为IPackageInstallerSession,这说明要通过
IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit
方法,这样代码逻辑就到了Java框架层的。
    // 调用IPackageInstallerSession的commit方法, 跨进程调用到
PackageInstallerSession.commit()
    mSession.commit(statusReceiver, false);
 } catch (RemoteException e) {
    throw e.rethrowFromSystemServer();
 }
}

PackageInstallerSession.commit()中

[PackageInstallerSession.java] commit()
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
  if (mIsPerfLockAcquired && mPerfBoostInstall != null) {
    mPerfBoostInstall.perfLockRelease();
    mIsPerfLockAcquired = false;
 }
 ...
  // 调用markAsCommitted()
  if (!markAsCommitted(statusReceiver, forTransfer)) {
    return;
 }
 ...
  // 【同学们注意】向Handler发送一个类型为MSG_COMMIT的消息 ,下面会分析
  mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
}

MSG_COMMIT在handler中进行处理,进入handleCommit()

public boolean handleMessage(Message msg) {
  switch (msg.what) {
    case MSG_COMMIT:
      handleCommit();
      break;
 }
}
private void handleCommit() {
 ...
  List<PackageInstallerSession> childSessions = getChildSessions();
  try {
    synchronized (mLock) {
      //最终调用installStage(),进入PKMS
      commitNonStagedLocked(childSessions);
   }
 } catch (PackageManagerException e) {
    final String completeMsg = ExceptionUtils.getCompleteMessage(e);
    Slog.e(TAG, "Commit of session " + sessionId + " failed: " +
completeMsg);
    destroyInternal();
    dispatchSessionFinished(e.error, completeMsg, null);
 }
}

最终调用 mPm.installStage(),进入PKMS 【经过千辛万苦,终于要进入PKMS了】

private void commitNonStagedLocked(...)throws PackageManagerException {
  if (isMultiPackage()) {
   ...
    mPm.installStage(activeChildSessions); // 【同学们注意】跨越进程 进入
PKMS.installStage了
 } else {
    mPm.installStage(committingSession);
 }
}

PKMS.installStage

[PackageManagerService.java]
void installStage(ActiveInstallSession activeInstallSession) {
  if (DEBUG_INSTANT) {
    if ((activeInstallSession.getSessionParams().installFlags
        & PackageManager.INSTALL_INSTANT_APP) != 0) {
      Slog.d(TAG, "Ephemeral install of " +
activeInstallSession.getPackageName());
   }
 }
  // 第一步.创建了类型为INIT_COPY的消息
  final Message msg = mHandler.obtainMessage(INIT_COPY);
  // 第二步.创建InstallParams,它对应于包的安装数据
  final InstallParams params = new InstallParams(activeInstallSession);
 params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(pa
rams));
  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));
 // 第三步.将InstallParams通过消息发送出去。
  mHandler.sendMessage(msg);
}
对INIT_COPY的消息的处理
[PackageManagerService.java]
void doHandleMessage(Message msg) {
  switch (msg.what) {
    case INIT_COPY: {
      HandlerParams params = (HandlerParams) msg.obj;
      if (params != null) {
        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(params));
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
        // 【同学们注意】执行APK拷贝动作,这里会执行到 final void startCopy()
        params.startCopy();
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
      break;
   }
 }
}
[PKMS.HandlerParams]
final void startCopy() {
      if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
      handleStartCopy(); 
      handleReturnCode();  // 调用到下面 handleReturnCode
   }
[PKMS.MultiPackageInstallParams]
void handleReturnCode() {
      if (mVerificationCompleted && mEnableRollbackCompleted) {
       .....
        if (mRet == PackageManager.INSTALL_SUCCEEDED) {
          mRet = mArgs.copyApk(); // 【同学们注意】 下面会说到 copyApk
       }
       .....
     }
}

APK 拷贝 方法调用步骤如下:

PKMS
copyApk()
doCopyApk()
PackageManagerServiceUtils
copyPacakge()
copyFile()
// TODO 通过文件流的操作,把APK拷贝到/data/app等目录
private static void copyFile(String sourcePath, File targetDir, String
targetName)
    throws ErrnoException, IOException {
  if (!FileUtils.isValidExtFilename(targetName)) {
    throw new IllegalArgumentException("Invalid filename: " + targetName);
 }
  Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
  final File targetFile = new File(targetDir, targetName);
  final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
      O_RDWR | O_CREAT, 0644);
  Os.chmod(targetFile.getAbsolutePath(), 0644);
  FileInputStream source = null;
  try {
    source = new FileInputStream(sourcePath);
    FileUtils.copy(source.getFD(), targetFd);
 } finally {
    IoUtils.closeQuietly(source);
 }
}

进入 Android 10.0 核心安装环节:

processPendingInstall:

private void processPendingInstall(final InstallArgs args, final int
currentStatus) {
  if (args.mMultiPackageInstallParams != null) {
    args.mMultiPackageInstallParams.tryProcessInstallRequest(args,
currentStatus);
 } else {
    //1.设置安装参数
    PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
    //2.创建一个新线程,处理安装参数,进行安装
    processInstallRequestsAsync(
        res.returnCode == PackageManager.INSTALL_SUCCEEDED,
        Collections.singletonList(new InstallRequest(args, res)));
 }
}
private void processInstallRequestsAsync(boolean success,
    List<InstallRequest> installRequests) {
  mHandler.post(() -> {
    if (success) {
      for (InstallRequest request : installRequests) {
        //1.如果之前安装失败,清除无用信息
        request.args.doPreInstall(request.installResult.returnCode);
     }
      synchronized (mInstallLock) {
        //2. installPackagesTracedLI 是安装过程的核心方法,然后调用
installPackagesLI 进行安装。
        // 【同学们注意】下面会分析此函数 installPackagesTracedLI
        installPackagesTracedLI(installRequests);
     }
      for (InstallRequest request : installRequests) {
        //3.如果之前安装失败,清除无用信息
        request.args.doPostInstall(
            request.installResult.returnCode,
request.installResult.uid);
     }
   }
    for (InstallRequest request : installRequests) {
      restoreAndPostInstall(request.args.user.getIdentifier(),
request.installResult,
          new PostInstallData(request.args, request.installResult,
null));
   }
 });
}

installPackagesTracedLI

private void installPackagesLI(List<InstallRequest> requests) {
 ...
  // 环节一.Prepare 准备:分析任何当前安装状态,分析包并对其进行初始验证。
  prepareResult = preparePackageLI(request.args, request.installResult);
 ...
  // 环节二.Scan 扫描:考虑到prepare中收集的上下文,询问已分析的包。
  final List<ScanResult> scanResults = scanPackageTracedLI(
              prepareResult.packageToScan,
prepareResult.parseFlags,
              prepareResult.scanFlags, System.currentTimeMillis(),
              request.args.user);
 ...
  // 环节三.Reconcile 调和:在彼此的上下文和当前系统状态中验证扫描的包,以确保安装成功
  ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans,
installArgs,
      installResults,
      prepareResults,
      mSharedLibraries,
      Collections.unmodifiableMap(mPackages), versionInfos,
      lastStaticSharedLibSettings);
 ...
  // 环节四.Commit 提交:提交所有扫描的包并更新系统状态。这是安装流中唯一可以修改系统状态的
地方,必须在此阶段之前确定所有可预测的错误。
  commitPackagesLocked(commitRequest);
 ...
  // 环节五.完成APK的安装【同学们注意:下面会分析这个操作】
  executePostCommitSteps(commitRequest);
}

executePostCommitSteps 安装APK,并为新的代码路径准备应用程序配置文件,并再次检查是否需要
dex优化
如果是直接安装新包,会为新的代码路径准备应用程序配置文件
如果是替换安装:其主要过程为更新设置,清除原有的某些APP数据,重新生成相关的app数据目录等
步骤,同时要区分系统应用替换和非系统应用替换。而安装新包:则直接更新设置,生成APP数据即可。

[PackageManagerService.java] executePostCommitSteps()
private void executePostCommitSteps(CommitRequest commitRequest) {
  for (ReconciledPackage reconciledPkg :
commitRequest.reconciledPackages.values()) {
   ...
    //1)进行安装
    prepareAppDataAfterInstallLIF(pkg);
    //2)如果需要替换安装,则需要清楚原有的APP数据
    if (reconciledPkg.prepareResult.clearCodeCache) {
      clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE |
FLAG_STORAGE_CE
          | FLAG_STORAGE_EXTERNAL |
Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
   }
    //3)为新的代码路径准备应用程序配置文件。这需要在调用dexopt之前完成,以便任何安装时配
置文件都可以用于优化。
    mArtManagerService.prepareAppProfiles(
        pkg,
        resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
        /* updateReferenceProfileContent= */ true);
    final boolean performDexopt =
       (!instantApp || Global.getInt(mContext.getContentResolver(),
        Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
        && ((pkg.applicationInfo.flags &
ApplicationInfo.FLAG_DEBUGGABLE) == 0);
    if (performDexopt) {
    ...
      //4)执行dex优化
      mPackageDexOptimizer.performDexOpt(pkg,
          null /* instructionSets */,
          getOrCreateCompilerPackageStats(pkg),
          mDexManager.getPackageUseInfoOrDefault(packageName),
          dexoptOptions);
   }
    BackgroundDexOptService.notifyPackageChanged(packageName);
 }
}

prepareAppDataAfterInstallLIF:

通过一系列的调用,最终会调用到[Installer.java] createAppData()进行安装,交给installed进程
进行APK的安装
调用栈如下:
prepareAppDataAfterInstallLIF()
  |
prepareAppDataLIF()
 |
prepareAppDataLeafLIF()
 |
[Installer.java]
createAppData()
private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) {
 ...
  for (UserInfo user : um.getUsers()) {
   ...
    if (ps.getInstalled(user.id)) {
      // TODO: when user data is locked, mark that we're still dirty
      prepareAppDataLIF(pkg, user.id, flags);
   }
 }
}
private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags)
{
  if (pkg == null) {
    Slog.wtf(TAG, "Package was null!", new Throwable());
    return;
 }
  prepareAppDataLeafLIF(pkg, userId, flags);
  final int childCount = (pkg.childPackages != null) ?
pkg.childPackages.size() : 0;
  for (int i = 0; i < childCount; i++) {
    prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
 }
}
private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int
flags) {
 ...
  try {
    // 调用Installd守护进程的入口
    ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId,
flags,
        appId, seInfo, app.targetSdkVersion);
 } catch (InstallerException e) {
    if (app.isSystemApp()) {
      destroyAppDataLeafLIF(pkg, userId, flags);
      try {
        ceDataInode = mInstaller.createAppData(volumeUuid, packageName,
userId, flags,
            appId, seInfo, app.targetSdkVersion);
     } catch (InstallerException e2) {
       ...
     }
   }
 }
}

Installer.createAppData 收尾工作,安装完成后,更新设置,更新安装锁等:

[Installer.java]
public long createAppData(String uuid, String packageName, int userId, int
flags, int appId,
    String seInfo, int targetSdkVersion) throws InstallerException {
  if (!checkBeforeRemote()) return -1;
  try {
    // mInstalld 为IInstalld的对象,即通过Binder调用到 进程installd,最终调用
installd的createAppData()
    // 【同学们注意】 mInstalld是一个aidl文件,通过此aidl文件调用到 Binder机制的服务
端,服务端哪里要操控底层....
    return mInstalld.createAppData(uuid, packageName, userId, flags, appId,
seInfo,
        targetSdkVersion);
 } catch (Exception e) {
    throw InstallerException.from(e);
 }
}

总结:安装的原理:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值