Android源码解析:Intent实现原理

(一)Intent查找与匹配

Android使用Intent进行组件,进程之间的通信和跳转。Intent具有隐式Intent和显式Intent两种,Android系统通过PackageManagerService来进行系统组件的维护。

系统启动之后会注册各种系统服务,其中就包括PackageManagerService。在启动之后,PMS会扫描已安装的apk目录,解析apk包下的AndroidManifest.xml文件得到App的相关信息,而每个AndroidManifest.xml又包含了Activity,Service等组件的注册信息,当PMS扫描并且解析完信息后,就清晰地描绘出了整棵apk的信息树。

PackageManagerService的构造函数大概有700多行,它加载了系统已安装的各类apk,并加载了Framework资源和核心库。加载了资源和核心库之后才开始对扫描的指定目录下的apk文件进行解析。实现这一操作的代码是scanDirLi函数。

 private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
        final File[] files = dir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }

        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
            try {
                scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
            } catch (PackageManagerException e) {
                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());

                // Delete invalid userdata apps
                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                        e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                    removeCodePathLI(file);
                }
            }
        }
    }

其中scanPackageTracedLI实现了包扫描

  private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,
            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
        try {
            return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }
 private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
        PackageParser pp = new PackageParser();
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setDisplayMetrics(mMetrics);

        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
    }

在scanPackageLI方法中,系统会构建一个PackageParser(包解析器),并调用这个包解析器的parsePackage方法进行文件解析。

  public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }

这个方法会根据是否只有一个apk,分别调用不同的方法进行解析。

无论是parseClusterPackage还是parseMonolithicPackage方法,其中都调用到了parseBaseApk方法。这个方法才具体实现了解析一个AndroidManifest.xml文件的流程。

private Package parseBaseApk(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;

            if (!TextUtils.isEmpty(splitName)) {
                outError[0] = "Expected base APK, but found split " + splitName;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
                return null;
            }
        } catch (PackageParserException e) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
            return null;
        }

        final Package pkg = new Package(pkgName);

        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);

        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }

        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);

        sa.recycle();

        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
    }

可以清晰地看到它解析了apk的versionName,versionCode,baseVersionCode。那么apk的各个组件是在哪里解析的呢?

打开方法parseBaseApplication,我们的一切疑问都可以得到回答。

   private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError) {


            //代码省略
              if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                owner.activities.add(a);
            } else if (tagName.equals("receiver")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }


                owner.receivers.add(a);


            } else if (tagName.equals("service")) {
                Service s = parseService(owner, res, parser, flags, outError);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }


                owner.services.add(s);


            } else if (tagName.equals("provider")) {
                Provider p = parseProvider(owner, res, parser, flags, outError);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }
                owner.providers.add(p);
            }
            // 代码省略
     }

显而易见,这里系统将应用的各个组件解析出来,并且存入到了各个集合当中。

至此,整个信息树构建完毕,系统已经存储好了这个应用的组件信息。

(二)信息匹配

我们看一下调用intent的具体方法,一般情况下,我们都是使用startActivity这个方法的。我们跟进去看一下。

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

然后我们在看一下startActivityForResult方法。

//省略代码
 options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
//省略代码

其中核心代码是execStartActivity这个方法。

这个方法经过一系列调用,最终调用了resolveActivityInfo方法

 public ActivityInfo resolveActivityInfo(@NonNull PackageManager pm,
            @PackageManager.ComponentInfoFlags int flags) {
        ActivityInfo ai = null;
        if (mComponent != null) {
            try {
                ai = pm.getActivityInfo(mComponent, flags);
            } catch (PackageManager.NameNotFoundException e) {
                // ignore
            }
        } else {
            ResolveInfo info = pm.resolveActivity(
                this, PackageManager.MATCH_DEFAULT_ONLY | flags);
            if (info != null) {
                ai = info.activityInfo;
            }
        }

        return ai;
    }

这个方法会根据传进来的flags在PMS所存储的组件列表中挑选最合适的系统组件,进行回传。

因此整个流程就是:

在系统启动时,PackageManagerService就会启动,PMS将解析所有已安装的应用信息,构建信息表,当用户通过Intent跳转到某个组件时,会根据Intent中包含的信息到PMS中查找对应的组件列表,最后跳转到目标组件当中。

    原文作者:不明真相的吃瓜攻城狮
    原文地址: https://blog.csdn.net/zzg080643/article/details/79346685
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞