PMS-PackageManagerService

本文基于Android_9.0、kernel_3.18源码

PMS的作用

在讨论PMS作用之前,我们不妨考虑一个问题:如果我们想要打开一个app,要经历哪些过程?

1、遍历data/app目录找到apk
2、解析AndroidManifest.xml文件
3、找到要启动的Activity,加载class
4、实例化Activity对象,进行展示

显然如果每次启动一个app都进行这几步操作,是非常消耗资源的,因此google设计了PMS、AMS来完成这些工作:
前两步由PMS完成,在开机时解析xml,然后对解析的数据进行缓存,加快App启动速度;
后两步由AMS完成,在真正启动的时候进行操作。

PMS启动流程

PMS启动流程

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java
frameworks/base/core/java/android/content/pm/PackageParser.java

Binder(五)服务注册流程-发送注册请求可知:
手机开机后会启动system_server进程,然后调用SystemServer的main方法,在main方法中通过startBootstrapServices启动PMS。

private void startBootstrapServices() {
    ...
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    ...
}

1、PMS->main()

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注册
    ServiceManager.addService("package", m);
    final PackageManagerNative pmn = m.new PackageManagerNative();
    ServiceManager.addService("package_native", pmn);
    return m;
}

在PMS的main方法中,创建了PMS对象,然后向servicemanager注册服务。

2、PMS构造方法

public class Environment {
    ...
    private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");

    public static File getDataDirectory() {
        return DIR_ANDROID_DATA;
    }
    ...
}

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    // app的安装目录
    private static final File sAppInstallDir = new File(Environment.getDataDirectory(), "app");

    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        ...
        // 扫描App的安装目录
        scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
        ...
    }

    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags, long currentTime) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
        try {
            scanDirLI(scanDir, parseFlags, scanFlags, currentTime);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
    ...
}

PMS的构造方法代码比较多,这里只分析扫描app的操作,通过scanDirTracedLI()调用到scanDirLI()扫描安装目录。

3、scanDirLI()

private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
    final File[] files = scanDir.listFiles();
    ...
    // 新建ParallelPackageParser
    try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
            mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
            mParallelPackageParserCallback)) {
        
        int fileCount = 0;
        // 遍历找到app
        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
            // 线程池操作
            parallelPackageParser.submit(file, parseFlags);
            fileCount++;
        }
        // 遍历处理结果
        for (; fileCount > 0; fileCount--) {
            ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
            Throwable throwable = parseResult.throwable;
            int errorCode = PackageManager.INSTALL_SUCCEEDED;
            if (throwable == null) {
                ...
                try {
                    if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
                        scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags,
                                currentTime, null);
                    }
                } catch (PackageManagerException e) {...}
            }
            ...
        }
    }
}

在scanDirLI方法中:
首先, 新建ParallelPackageParser对象,用来解析;
然后, 遍历安装目录,判断是否是app目录;
再然后, 将得到的目录通过submit交由ParallelPackageParser处理;
最后, 得到结果后,通过scanPackageChildLI再次处理。

4、ParallelPackageParser

class ParallelPackageParser implements AutoCloseable {
    // 线程池
    private final ExecutorService mService = ConcurrentUtils.newFixedThreadPool(MAX_THREADS,
            "package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
    // 存储解析结果
    private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);

    public void submit(File scanFile, int parseFlags) {
        // 提交到线程池
        mService.submit(() -> {
            ParseResult pr = new ParseResult();
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
            try {
                // 新建PackageParser
                PackageParser pp = new PackageParser();
                pp.setSeparateProcesses(mSeparateProcesses);
                pp.setOnlyCoreApps(mOnlyCore);
                pp.setDisplayMetrics(mMetrics);
                pp.setCacheDir(mCacheDir);
                pp.setCallback(mPackageParserCallback);
                pr.scanFile = scanFile;

                // 对package进行解析
                pr.pkg = parsePackage(pp, scanFile, parseFlags);
            } catch (Throwable e) {
                pr.throwable = e;
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
            try {

                // 将处理结果添加到mQueue中
                mQueue.put(pr);
            } catch (InterruptedException e) {
                ...
            }
        });
    }

    @VisibleForTesting
    protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
                                                 int parseFlags) throws PackageParser.PackageParserException {
        return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
    }
    ...
}

ParallelPackageParser定义了mService线程池对数据进行解析;定义了BlockingQueue类型的mQueue对结果进行存储。

submit方法将解析任务提交给线程池,在任务中:创建PackageParser对象,借用它的parsePackage对package解析;解析完毕后,将解析结果添加到mQueue中。

5、PackageParser.java->parsePackage()

public PackageParser.Package parsePackage(File packageFile, int flags, boolean useCaches)
        throws PackageParser.PackageParserException {
    // 如果有缓存,直接返回缓存
    PackageParser.Package parsed = useCaches ? getCachedResult(packageFile, flags) : null
    if (parsed != null) {
        return parsed;
    }
    long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
    // 解析package
    if (packageFile.isDirectory()) {
        parsed = parseClusterPackage(packageFile, flags);
    } else {
        parsed = parseMonolithicPackage(packageFile, flags);
    }
    long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
    // 缓存
    cacheResult(packageFile, flags, parsed);
    ...
    return parsed;
}

首先, 通过getCachedResult查找本地缓存,如果有的话直接返回;
然后, 对package解析;
最后, 通过cacheResult对解析结果进行缓存。

6、包解析

private PackageParser.Package parseClusterPackage(File packageDir, int flags) throws PackageParser.PackageParserException {
    // 轻量解析
    final PackageParser.PackageLite lite = parseClusterPackageLite(packageDir, 0);
    ...
    try {
        final AssetManager assets = assetLoader.getBaseAssetManager();
        final File baseApk = new File(lite.baseCodePath);
        // 解析
        final PackageParser.Package pkg = parseBaseApk(baseApk, assets, flags);
        ...
        // 赋值
        if (!ArrayUtils.isEmpty(lite.splitNames)) {
            final int num = lite.splitNames.length;
            pkg.splitNames = lite.splitNames;
            pkg.splitCodePaths = lite.splitCodePaths;
            pkg.splitRevisionCodes = lite.splitRevisionCodes;
            pkg.splitFlags = new int[num];
            pkg.splitPrivateFlags = new int[num];
            pkg.applicationInfo.splitNames = pkg.splitNames;
            pkg.applicationInfo.splitDependencies = splitDependencies;
            pkg.applicationInfo.splitClassLoaderNames = new String[num];
            for (int i = 0; i < num; i++) {
                final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
                parseSplitApk(pkg, i, splitAssets, flags);
            }
        }
        pkg.setCodePath(packageDir.getCanonicalPath());
        pkg.setUse32bitAbi(lite.use32bitAbi);
        return pkg;
    } catch (IOException e) {...} finally {
        IoUtils.closeQuietly(assetLoader);
    }
}

public PackageParser.Package parseMonolithicPackage(File apkFile, int flags) throws PackageParser.PackageParserException {
    // 轻量解析
    final PackageParser.PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
    
    // 核心app的校验
    if (mOnlyCoreApps) {
        if (!lite.coreApp) {
            throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + apkFile);
        }
    }
    final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
    try {
        // 解析
        final PackageParser.Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
        pkg.setCodePath(apkFile.getCanonicalPath());
        pkg.setUse32bitAbi(lite.use32bitAbi);
        return pkg;
    } catch (IOException e) {...} finally {
        IoUtils.closeQuietly(assetLoader);
    }
}

Google在Android 5.0引入了Split APK机制,用来解决65536上限,以及APK安装包越来越大等问题;这样,apk就分为两类:
1、Single APK:安装文件为一个完整的APK;
2、Mutiple APK:安装文件在一个文件目录中,其内部有多个被拆分的APK,这些APK由一个 base APK和N个split APK组成。

因此解析的方式也分为两种,parseMonolithicPackage 用来解析single ApkparseClusterPackage 用来解析Mutiple Apk

它们内部都调用轻量解析parseBaseApk ,解析的主要操作基本一致。

7、parseBaseApk()

public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
private PackageParser.Package parseBaseApk(File apkFile, AssetManager assets, int flags)
        throws PackageParser.PackageParserException {
    final String apkPath = apkFile.getAbsolutePath();
    ...
    XmlResourceParser parser = null;
    try {
        final int cookie = assets.findCookieForPath(apkPath);
        if (cookie == 0) {
            throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
                    "Failed adding asset path: " + apkPath);
        }
        // 打开AndroidManifest.xml文件
        parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
        final Resources res = new Resources(assets, mMetrics, null);
        final String[] outError = new String[1];
        // 解析
        final PackageParser.Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
        ...
        return pkg;
    } catch (PackageParser.PackageParserException e) {...} catch (Exception e) {...} finally {
        IoUtils.closeQuietly(parser);
    }
}

在parseBaseApk中,打开AndroidManifest.xml文件,然后调用parseBaseApk重载方法进行解析。

private PackageParser.Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags
                                           String[] outError) throws XmlPullParserException, IOException {
    final String splitName;
    final String pkgName;
    try {
        // 解析包名
        Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
        pkgName = packageSplit.first;
        splitName = packageSplit.second;
        ...
    } catch (PackageParser.PackageParserException e) {...}
    ...
    final PackageParser.Package pkg = new PackageParser.Package(pkgName);
    // 解析app相关参数
    TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifest);
    pkg.mVersionCode = sa.getInteger(
            com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
    pkg.mVersionCodeMajor = sa.getInteger(
            com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
    ...
    return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
}

在重载方法中,解析包名,然后创建Package对象,并且解析一些app的基础参数:VersionCode、VersionName等;最后通过parseBaseApkCommon进一步解析。

8、parseBaseApkCommon()

private PackageParser.Package parseBaseApkCommon(PackageParser.Package pkg, Set<String> acceptedTags, Resources res,
                                                 XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
        IOException {
    int type;
    boolean foundApp = false;
    TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifest);
    ...
    // 解析标签
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        String tagName = parser.getName();
        ...
        // 解析application标签
        if (tagName.equals(TAG_APPLICATION)) {
            ...
            if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
                return null;
            }
        } else if (tagName.equals(TAG_OVERLAY)) {
            ...
        } else if (tagName.equals(TAG_KEY_SETS)) {
            ...
        } else if (tagName.equals(TAG_PERMISSION_GROUP)) {// 解析权限
            ...
        } else if (tagName.equals(TAG_PERMISSION)) {// 解析权限
            ...
        } else if (tagName.equals(TAG_PERMISSION_TREE)) {
            ...
        } else if (tagName.equals(TAG_USES_PERMISSION)) {
            ...
        } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
                || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
            ...
        } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
            ...
        } else if (tagName.equals(TAG_USES_FEATURE)) {
            ...
        } else if (tagName.equals(TAG_FEATURE_GROUP)) {
            ...
        } else if (tagName.equals(TAG_USES_SDK)) {
            ...
        } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
            ...
        } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
            ...
        } else if (tagName.equals(TAG_INSTRUMENTATION)) {
            ...
        } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
            ...
        } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
            ...
        } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
            ...
        } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
            ...
        } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
            ...
        } else if (tagName.equals(TAG_EAT_COMMENT)) {
            ...
        } else if (tagName.equals(TAG_PACKAGE)) {
            ...
        } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
            ...
        } else if (RIGID_PARSER) {
            ...
        } else {
            ...
        }
    }
    ...
    return pkg;
}

该方法会对AndroidManifest.xml中的标签进行解析,包括application、uses-permission等,我们主要关注对application的解析。

9、parseBaseApplication()

private boolean parseBaseApplication(PackageParser.Package owner, Resources res,
                                     XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
    final ApplicationInfo ai = owner.applicationInfo;
    final String pkgName = owner.applicationInfo.packageName;
    TypedArray sa = res.obtainAttributes(parser,
            com.android.internal.R.styleable.AndroidManifestApplication);
    // 解析application定义的内容,名称、icon等
    if (!parsePackageItemInfo(owner, ai, outError,
            "<application>", sa, false /*nameRequired*/,
            com.android.internal.R.styleable.AndroidManifestApplication_name,
            com.android.internal.R.styleable.AndroidManifestApplication_label,
            com.android.internal.R.styleable.AndroidManifestApplication_icon,
            com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
            com.android.internal.R.styleable.AndroidManifestApplication_logo,
            com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
        sa.recycle();
        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
        return false;
    }
    ...
    int type;
    boolean hasActivityOrder = false;
    boolean hasReceiverOrder = false;
    boolean hasServiceOrder = false;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        String tagName = parser.getName();
        if (tagName.equals("activity")) {// 解析activity
            PackageParser.Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                    owner.baseHardwareAccelerated);
            ...
            // 添加到package中
            owner.activities.add(a);
        } else if (tagName.equals("receiver")) {// 解析receiver
            PackageParser.Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
                    true, false);
            ...
            owner.receivers.add(a);
        } else if (tagName.equals("service")) {// 解析service
            PackageParser.Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
            ...
            owner.services.add(s);
        } else if (tagName.equals("provider")) {// 解析provider
            ...
            owner.providers.add(p);
        } else if (tagName.equals("activity-alias")) {
            ...
        } else if (parser.getName().equals("meta-data")) {
            ...
        } else if (tagName.equals("static-library")) {
            ...
        } else if (tagName.equals("library")) {
            ...
        } else if (tagName.equals("uses-static-library")) {
            ...
        } else if (tagName.equals("uses-library")) {
            ...
        } else if (tagName.equals("uses-package")) {
            ...
        } else {
            ...
        }
    }
    // 排序
    if (hasActivityOrder) {
        Collections.sort(owner.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
    }
    if (hasReceiverOrder) {
        Collections.sort(owner.receivers, (r1, r2) -> Integer.compare(r2.order, r1.order));
    }
    if (hasServiceOrder) {
        Collections.sort(owner.services, (s1, s2) -> Integer.compare(s2.order, s1.order));
    }
    ...
    return true;
}

对四大组件进行解析,并加入到package中。具体的解析内容无非是对于xml各种标签的识别,不再详述。

10、scanPackageChildLI()

private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg,
                                                 final @ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, long currentTime,
                                                 @Nullable UserHandle user)
        throws PackageManagerException {
    ...
    // Scan the parent
    PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags,
            scanFlags, currentTime, user);
    // Scan the children
    final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
    for (int i = 0; i < childCount; i++) {
        PackageParser.Package childPackage = pkg.childPackages.get(i);
        addForInitLI(childPackage, parseFlags, scanFlags,
                currentTime, user);
    }
    if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
        return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
    }
    return scannedPkg;
}

private PackageParser.Package addForInitLI(PackageParser.Package pkg,
                                           @ParseFlags int parseFlags, @PackageManagerService.ScanFlags int scanFlags, long currentTime,
                                           @Nullable UserHandle user)
        throws PackageManagerException {
    ...
    if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
        ...
        synchronized (mPackages) {
            if (!mPackages.containsKey(pkg.packageName)) {
                mPackages.put(pkg.packageName, pkg);
            }
        }
        ...
    }
    ...
    final PackageParser.Package scannedPkg = scanPackageNewLI(pkg, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);
    ...
    return scannedPkg;
}

回到scanDirLI中,代码会从mQueue中取到解析的结果,进行扫描;然后通过addForInitLI将结果缓存到PMS的mPackages中。

11、commitPackageSettings

private void commitPackageSettings(PackageParser.Package pkg,
        @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, UserHandle user,
        final @ScanFlags int scanFlags, boolean chatty) {
     ...
     mProviders.addProvider(p);
     ...
     mServices.addService(s);
     ...     
     mReceivers.addActivity(a, "receiver");
     ...
     mActivities.addActivity(a, "activity");
}

在scanPackageNewLI中,会通过如下调用链scanPackageNewLI->commitScanResultsLocked->commitPackageSettings调用到commitPackageSettings,将四大组件的信息缓存在PMS中。

至此,整个package解析完毕,通过解析生成package实体,其中包括app的基础信息、权限配置、四大组件信息等;并通过PMS的mPackages进行缓存。

新应用安装的解析流程

apk安装PMS解析流程

packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
xref/frameworks/base/core/java/android/content/pm/PackageInstaller.java

PackageInstallerActivity----InstallInstalling-----

通过adb shell 命令,结合dumpsys window | grep mCurrentFocus 可以看到当前运行的界面,在安装apk的时候,我们可以看到,最终是通过com.android.packageinstaller.InstallInstalling 页面进行安装。

手机安装界面

1、InstallInstalling

public class InstallInstalling extends Activity {
    ...
    @Override
    protected void onResume() {
        ...
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

            if (sessionInfo != null && !sessionInfo.isActive()) {
                // 创建InstallingAsyncTask
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            } else {...}
        }
    }

    private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {
        volatile boolean isDone;

        @Override
        protected PackageInstaller.Session doInBackground(Void... params) {
            PackageInstaller.Session session;
            try {
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                return null;
            }
            ...
        }

        @Override
        protected void onPostExecute(PackageInstaller.Session session) {
            if (session != null) {
                ...
                // 通过session.commi通知PMS
                session.commit(pendingIntent.getIntentSender());
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            } else {...}
        }
    }
    ...
}

在onResume中创建InstallingAsyncTask并启动,在InstallingAsyncTask中,执行完doInBackground后通过session.commit通知PMS。

2、PackageInstallerSession.commit

PackageInstaller.Session.commit会通过aidl 调用到PackageInstallerSession.commit,之后的事情发生在服务端。

@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    ...
    synchronized (mLock) {
        ...
        mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
    }
    ...
}

private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_EARLY_BIND:
                ...
                break;
            case MSG_COMMIT:
                synchronized (mLock) {
                    try {
                        commitLocked();
                    } catch (PackageManagerException e) {...}
                }
                break;
            ...
        }
        return true;
    }
};

在mHandlerCallback中通过commitLocked进行处理。

3、commitLocked

private void commitLocked()
        throws PackageManagerException {
    ...
    mPm.installStage(mPackageName, stageDir, localObserver, params,
            mInstallerPackageName, mInstallerUid, user, mSigningDetails);
}

通过commitLocked会调用到PMS的installStage。

4、installStage

void installStage(String packageName, File stagedDir,
        IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
        String installerPackageName, int installerUid, UserHandle user,
        PackageParser.SigningDetails signingDetails) {
    ...
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    ...
    final InstallParams params = new InstallParams(origin, null, observer,
            sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
            verificationInfo, user, sessionParams.abiOverride,
            sessionParams.grantedRuntimePermissions, signingDetails, installReason);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;
    ...
    mHandler.sendMessage(msg);
}

生成InstallParams,并发送INIT_COPY由handler处理。

5、消息处理

public void handleMessage(Message msg) {
    try {
        doHandleMessage(msg);
    } finally {...}
}

void doHandleMessage(Message msg) {
    switch (msg.what) {
        ...
        case INIT_COPY: {
            // 获取params,注意这里是InstallParams类型
            HandlerParams params = (HandlerParams) msg.obj;
            ...
            if (!mBound) {...} else {
                // 添加到mPendingInstalls中
                mPendingInstalls.add(idx, params);
                // Already bound to the service. Just make
                // sure we trigger off processing the first request.
                if (idx == 0) {
                    // 如果是第一个,则发送启动消息
                    mHandler.sendEmptyMessage(MCS_BOUND);
                }
            }
            break;
        }
        case MCS_BOUND: {
            ...
            if (mContainerService == null) {
                ...
            } else if (mPendingInstalls.size() > 0) {
                // 获取params,注意这里是InstallParams类型
                HandlerParams params = mPendingInstalls.get(0);
                if (params != null) {
                    ...
                    // 调用startCopy
                    if (params.startCopy()) {
                        ...
                        if (mPendingInstalls.size() > 0) {
                            mPendingInstalls.remove(0);
                        }
                        if (mPendingInstalls.size() == 0) {
                            ...
                        } else {
                            ...
                            // 如果没处理完,继续处理
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                }
            } else {...}
            break;
        }
        ...
    }
}

获取params,加入mPendingInstalls中,如果插入的位置使0,则发送消息MCS_BOUND开始处理。在MCS_BOUND分支中,会调用params的startCopy。

6、startCopy

final boolean startCopy() {
    boolean res;
    ...
    handleReturnCode();
    return res;
}

class InstallParams extends HandlerParams {
    void handleReturnCode() {
        if (mArgs != null) {
            processPendingInstall(mArgs, mRet);
        }
    }
}

在startCopy中,会调用到handleReturnCode,由于真实的params是InstallParams,所以会调用到processPendingInstall。

7、processPendingInstall

private void processPendingInstall(final InstallArgs args, final int currentStatus) {
    // Queue up an async operation since the package installation may take a little while.
    mHandler.post(new Runnable() {
        public void run() {
            ...
            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                args.doPreInstall(res.returnCode);
                synchronized (mInstallLock) {
                    installPackageTracedLI(args, res);
                }
                args.doPostInstall(res.returnCode, res.uid);
            }
            ...
        }
    });
}

private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
    try {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
        installPackageLI(args, res);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
}

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
    ...
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setDisplayMetrics(mMetrics);
    pp.setCallback(mPackageParserCallback);
    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
        pkg = pp.parsePackage(tmpPackageFile, parseFlags);
        DexMetadataHelper.validatePackageDexMetadata(pkg);
    } catch (PackageParserException e) {
        res.setError("Failed parse during installPackageLI", e);
        return;
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    ...
}

processPendingInstall会通过handler调用installPackageTracedLI方法,进而调用到installPackageLI,在这里我们可以看到是通过PackageParser.parsePackage方法对package进行解析;与前半部分分析便对上了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值