PMS解析已安装的apk信息

在Android中getSystemService流程一文中,我们知道系统在启动的时候
会加载系统Service,比如ActivityManagerService,PackageManagerService等, PMS启动以后,会扫描系统中所有已安装apk的目录,比如系统
应用”/system/app”,第三方应用”/data/app”,PMS会解析该包下的所有AndroidManifest.xml文件,将解析出的activity,service,broadcastreceiver
等信息保存到系统中。

其实在android系统开机以后加载PackageManagerService时候,从其构造方法就开始了。

public PackageManagerService(Context context, Installer installer,            boolean factoryTest, boolean onlyCore) {        .......        synchronized (mInstallLock) {        // writer        synchronized (mPackages) {            mHandlerThread = new ServiceThread(TAG,                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);            mHandlerThread.start();            mHandler = new PackageHandler(mHandlerThread.getLooper());            // 获取/data目录            File dataDir = Environment.getDataDirectory();            // /data/data            mAppDataDir = new File(dataDir, "data");            // /data/app            mAppInstallDir = new File(dataDir, "app");            mAppLib32InstallDir = new File(dataDir, "app-lib");            mAsecInternalPath = new File(dataDir, "app-asec").getPath();            mUserAppDataDir = new File(dataDir, "user");            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");            mRegionalizationAppInstallDir = new File(dataDir, "app-regional");            .....            File frameworkDir = new File(Environment.getRootDirectory(), "framework");            // 加载framework资源            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");            // 加载核心库文件            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");            populateBlacklist();            .....            // 获取系统app的安装路径            final File systemAppDir = new File(Environment.getRootDirectory(), "app");            // 扫描系统app的安装路径            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_RUNTIME_SKIN, 0);            // Collect all vendor packages.            File vendorAppDir = new File("/vendor/app");            try {                vendorAppDir = vendorAppDir.getCanonicalFile();            } catch (IOException e) {                // failed to look up canonical path, continue with original one            }            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_RUNTIME_SKIN, 0);            // Collect all OEM packages.            final File oemAppDir = new File(Environment.getOemDirectory(), "app");            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_RUNTIME_SKIN, 0);            File oemPrivAppDir = new File(Environment.getOemDirectory(), "priv-app");            if (oemPrivAppDir.exists()) {                scanDirLI(oemPrivAppDir, PackageParser.PARSE_IS_SYSTEM                        | PackageParser.PARSE_IS_SYSTEM_DIR                        | PackageParser.PARSE_IS_PRIVILEGED,                        scanFlags | SCAN_TRUSTED_RUNTIME_SKIN, 0);            }            // Collect all Regionalization packages form Carrier's res packages.            if (RegionalizationEnvironment.isSupported()) {                Log.d(TAG, "Load Regionalization vendor apks");                final List RegionalizationDirs =                        RegionalizationEnvironment.getAllPackageDirectories();                for (File f : RegionalizationDirs) {                    File RegionalizationSystemDir = new File(f, "system");                    // Collect packages in /system/priv-app                    scanDirLI(new File(RegionalizationSystemDir, "priv-app"),                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR                            | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);                    // Collect packages in /system/app                    scanDirLI(new File(RegionalizationSystemDir, "app"),                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,                            scanFlags, 0);                    // Collect overlay in /system/vendor                    scanDirLI(new File(RegionalizationSystemDir, "vendor/overlay"),                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,                            scanFlags | SCAN_TRUSTED_OVERLAY, 0);                }            }            if (!mOnlyCore) {                // 扫描第三方app的安装路径                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,                        scanFlags | SCAN_REQUIRE_KNOWN, 0);            }            .....        } // synchronized (mPackages)        } // synchronized (mInstallLock)        Runtime.getRuntime().gc();        // Expose private service for system components to use.        LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());        LocalServices.addService(PackageManagerServiceExtend.class, new ServiceExtendImpl());}

从上面的构造方法,可以看出,PMS需要加载系统已安装的各类apk,包括系统apk第三方apk等等,在此之前,还要加载Framework资源与核心库文件,
并且具体的扫描加载功能由scanDirLI方法实现,我们看看scanDirLI方法的内部实现:

private void scanDirLI(File dir, 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;        }        // 遍历所有文件        for (File file : files) {            final boolean isPackage = (isApkFile(file) || file.isDirectory())                    && !PackageInstallerService.isStageName(file.getName());            // 如果不是apk文件,则直接忽略            if (!isPackage) {                continue;            }            ......            try {                // 解析apk                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,                        scanFlags, currentTime, null);            } catch (PackageManagerException e) {                .....            }        }}

scanDirLI方法比较简单:
1. 遍历当前目录下所有文件,如果没有文件,直接返回
2. 判断当前文件是否是apk文件,如果不是直接返回
3. 通过scanPackageLI解析当前apk文件

可以看到重点解析当前apk文件的工作,转移到了scanPackageLI方法,我们继续scanPackageLI:

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,                                                long currentTime, UserHandle user) throws PackageManagerException {        // 创建一个包解析器        PackageParser pp = new PackageParser();        pp.setSeparateProcesses(mSeparateProcesses);        pp.setOnlyCoreApps(mOnlyCore);        pp.setDisplayMetrics(mMetrics);        pp.setRuntimeSkinBlacklist(mRuntimeSkinManager.getBlacklistedPackages());        final PackageParser.Package pkg;        try {            // 解析apk包            pkg = pp.parsePackage(scanFile, parseFlags);        } catch (PackageParser.PackageParserException e) {            throw PackageManagerException.from(e);        }        ....        // 解析apk中的activity,service等组件, 在(pkg, parseFlags, scanFlags        //        | SCAN_UPDATE_SIGNATURE, currentTime, user)方法中会将当前解析出的activity,service等组件添加到PackageManagerService的集合里        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags                | SCAN_UPDATE_SIGNATURE, currentTime, user);        ....        return scannedPkg;}

在scanPackageLI方法中:
1.首先创建一个包解析器
2.通过parsePackage解析apk包,封装成PackageParser.Package类型
3.通过步骤二中的PackageParser.Package对象,解析apk中的activity,service等组件

解析单个apk

下面我们看下parsePackage方法,具体解析单个apk文件的流程:

public Package parsePackage(File packageFile, int flags) throws PackageParserException {        // 是否是文件夹类型        if (packageFile.isDirectory()) {            return parseClusterPackage(packageFile, flags);        } else {            // 解析单个apk文件            return parseMonolithicPackage(packageFile, flags);        }}

在parsePackage中,会判断当前文件类型选择不同的解析,如果是一个文件夹,则匹配该文件夹下的所有apk文件,如果是一个文件,则调用
PackageParser#parseMonolithicPackage解析单个文件。

public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {        ...        final AssetManager assets = new AssetManager();        try {            // 具体解析apk文件操作的封装            final Package pkg = parseBaseApk(apkFile, assets, flags);            pkg.codePath = apkFile.getAbsolutePath();            return pkg;        } finally {            IoUtils.closeQuietly(assets);        }}private Package parseBaseApk(File apkFile, AssetManager assets, int flags)            throws PackageParserException {        final String apkPath = apkFile.getAbsolutePath();        // 代码省略        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);        Resources res = null;        XmlResourceParser parser = null;        try {            // 根据AssetManager实例构建资源实例            res = new 构建(assets, mMetrics, null);            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                    Build.VERSION.RESOURCES_SDK_INT);            // 获取AndroidManifest.xml的解析器            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);            final String[] outError = new String[1];            // 解析获取到的AndroidManifest.xml            final Package pkg = parseBaseApk(res, parser, flags, outError);            pkg.volumeUuid = volumeUuid;            pkg.applicationInfo.volumeUuid = volumeUuid;            pkg.baseCodePath = apkPath;            pkg.mSignatures = null;            return pkg;        }        // 省略catch代码块}

在上述方法中主要调用了parseBaseApk(res, parser, flags, outError)解析AndroidManifest.xml文件

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,                                 String[] outError) throws XmlPullParserException, IOException {        AttributeSet attrs = parser;        // 1.构建Package对象        final Package pkg = new Package(pkgName);        boolean foundApp = false;        // 2.通过TypedArray获取AndroidManifest.xml文件中的属性值,并赋值给pkg对象        TypedArray sa = res.obtainAttributes(attrs,                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();        }        String str = sa.getNonConfigurationString(                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);        if (str != null && str.length() > 0) {            String nameError = validateName(str, true, false);            if (nameError != null && !"android".equals(pkgName)) {                outError[0] = " specifies bad sharedUserId name \""                        + str + "\": " + nameError;                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;                return null;            }            pkg.mSharedUserId = str.intern();            pkg.mSharedUserLabel = sa.getResourceId(                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);        }        pkg.installLocation = sa.getInteger(                com.android.internal.R.styleable.AndroidManifest_installLocation,                PARSE_DEFAULT_INSTALL_LOCATION);        pkg.applicationInfo.installLocation = pkg.installLocation;        pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);        sa.recycle();        // 3.解析AndroidManifest.xml文件        int outerDepth = parser.getDepth();        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();            if (tagName.equals("application")) {                if (foundApp) {                // 4.解析application标签,activity,service,broadcastreceiver都在这个标签中                if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {                    return null;                }            } else if (tagName.equals("overlay")) {               ....            } else if (tagName.equals("key-sets")) {                if (!parseKeySets(pkg, res, parser, attrs, outError)) {                    return null;                }            } else if (tagName.equals("permission-group")) {                if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {                    return null;                }            } else if (tagName.equals("permission")) {                if (parsePermission(pkg, res, parser, attrs, outError) == null) {                    return null;                }            } else if (tagName.equals("permission-tree")) {                if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {                    return null;                }            } else if (tagName.equals("uses-permission")) {                if (!parseUsesPermission(pkg, res, parser, attrs)) {                    return null;                }            } else if (tagName.equals("uses-permission-sdk-m")                    || tagName.equals("uses-permission-sdk-23")) {                if (!parseUsesPermission(pkg, res, parser, attrs)) {                    return null;                }            } else if (tagName.equals("uses-configuration")) {                ....            } else if (tagName.equals("uses-feature")) {                ....            } else if (tagName.equals("feature-group")) {                ....            } else if (tagName.equals("uses-sdk")) {                ....            } else if (tagName.equals("supports-screens")) {                ....            } else if (tagName.equals("protected-broadcast")) {                ....            } else if (tagName.equals("adopt-permissions")) {                ....            }        }        ....        return pkg;}

在PackageParser#parseBaseApk(res, parser, flags, outError)方法主要做了下面的事情:

  • 构建Package对象
  • 通过TypedArray获取AndroidManifest.xml文件中的属性值,并赋值给pkg对象
  • 解析AndroidManifest.xml文件
  • 通过parseBaseApplication解析application标签,activity,service,broadcastreceiver都在这个标签中

接着分析parseBaseApplication方法:

private boolean parseBaseApplication(Package owner, Resources res,                                         XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)            throws XmlPullParserException, IOException {        final ApplicationInfo ai = owner.applicationInfo;        final String pkgName = owner.applicationInfo.packageName;        // 根据TypedArray获取到在AndroidManifest.xml文件中配置的属性值.        TypedArray sa = res.obtainAttributes(attrs,                com.android.internal.R.styleable.AndroidManifestApplication);        // 省略代码        ai.icon = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);        ai.logo = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);        ai.banner = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);        ai.theme = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);        ai.descriptionRes = sa.getResourceId(                com.android.internal.R.styleable.AndroidManifestApplication_description, 0);        // 省略代码        sa.recycle();        // 2.解析AndroidManifest.xml中的四大组件,并且将解析结果,添加到Package中对应的集合里        final int innerDepth = parser.getDepth();        int type;        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 a = parseActivity(owner, res, parser, attrs, 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, attrs, 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, attrs, 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, attrs, flags, outError);                if (p == null) {                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return false;                }                owner.providers.add(p);            } else if (tagName.equals("activity-alias")) {                Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);                if (a == null) {                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return false;                }                owner.activities.add(a);            }        return true;}

在parseBaseApplication主要做了下面操作:
1. 根据TypedArray获取到在AndroidManifest.xml文件中配置的属性值.
2. 解析AndroidManifest.xml中的四大组件,并且将解析结果,添加到Package中对应的集合里,这些集合是声明在PackageParser$Package中的

public final static class Package {    ....    public final ArrayList activities = new ArrayList(0);    public final ArrayList receivers = new ArrayList(0);    public final ArrayList providers = new ArrayList(0);    public final ArrayList services = new ArrayList(0);}

到此位置解析单个apk的工作都已经完成,并且将解析结果封装到Package对象中

将解析结果信息存储到PackageManagerService的集合里

回到上面的scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user)方法,

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,                                                long currentTime, UserHandle user) throws PackageManagerException {        // 创建一个包解析器        PackageParser pp = new PackageParser();        pp.setSeparateProcesses(mSeparateProcesses);        pp.setOnlyCoreApps(mOnlyCore);        pp.setDisplayMetrics(mMetrics);        pp.setRuntimeSkinBlacklist(mRuntimeSkinManager.getBlacklistedPackages());        final PackageParser.Package pkg;        try {            // 解析apk包            pkg = pp.parsePackage(scanFile, parseFlags);        } catch (PackageParser.PackageParserException e) {            throw PackageManagerException.from(e);        }        ....        // 解析apk中的activity,service等组件, 在(pkg, parseFlags, scanFlags        //        | SCAN_UPDATE_SIGNATURE, currentTime, user)方法中会将当前解析出的activity,service等组件添加到PackageManagerService的集合里        PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags                | SCAN_UPDATE_SIGNATURE, currentTime, user);        ....        return scannedPkg;}

在该方法,最后调用了scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user)方法:

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {   .....N = pkg.services.size();    r = null;    for (i=0; i        PackageParser.Service s = pkg.services.get(i);        s.info.processName = fixProcessName(pkg.applicationInfo.processName,                s.info.processName, pkg.applicationInfo.uid);        // 添加到对应的mServices集合中        mServices.addService(s);        if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {            if (r == null) {                r = new StringBuilder(256);            } else {                r.append(' ');            }            r.append(s.info.name);        }    }    if (r != null) {        if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Services: " + r);    }    N = pkg.receivers.size();    r = null;    for (i=0; i        PackageParser.Activity a = pkg.receivers.get(i);        a.info.processName = fixProcessName(pkg.applicationInfo.processName,                a.info.processName, pkg.applicationInfo.uid);        // 添加到对应的mReceivers集合中        mReceivers.addActivity(a, "receiver");        if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {            if (r == null) {                r = new StringBuilder(256);            } else {                r.append(' ');            }            r.append(a.info.name);        }    }    if (r != null) {        if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, "  Receivers: " + r);    }    N = pkg.activities.size();    r = null;    for (i=0; i        PackageParser.Activity a = pkg.activities.get(i);        a.info.processName = fixProcessName(pkg.applicationInfo.processName,                a.info.processName, pkg.applicationInfo.uid);        // 添加到对应的mActivities集合中        mActivities.addActivity(a, "activity");        if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {            if (r == null) {                r = new StringBuilder(256);            } else {                r.append(' ');            }            r.append(a.info.name);        }    }   ....}

将之前保存在PackageParser.Package中的apk信息重新放到PackageManagerService中

final ActivityIntentResolver mActivities =            new ActivityIntentResolver();// All available receivers, for your resolving pleasure.final ActivityIntentResolver mReceivers =            new ActivityIntentResolver();// All available services, for your resolving pleasure.final ServiceIntentResolver mServices = new ServiceIntentResolver();// All available providers, for your resolving pleasure.final ProviderIntentResolver mProviders = new ProviderIntentResolver();

到现在为止所有apk信息的构建就完成了。

intent信息的匹配

这里我们用”startActivity”来说明,在activity启动流程一文中,我们详细的讨论过activity的启动流程
ActivityStackSupervisor#startActivityMayWait方法

final int startActivityMayWait(参数省略.....) {    try {           ResolveInfo rInfo =                                AppGlobals.getPackageManager().resolveIntent(                                        intent, null,                                        PackageManager.MATCH_DEFAULT_ONLY                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);                            aInfo = rInfo != null ? rInfo.activityInfo : null;                            aInfo = mService.getActivityInfoForUser(aInfo, userId);    } catch (RemoteException e) {          aInfo = null;    }     int res = startActivityLocked(caller, intent, resolvedType, aInfo,                    voiceSession, voiceInteractor, resultTo, resultWho,                    requestCode, callingPid, callingUid, callingPackage,                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,                    componentSpecified, null, container, inTask);    return res;}

可以看到通过PMS中的resolveIntent方法来查找匹配当前intent的activity

@Overridepublic ResolveInfo resolveIntent(Intent intent, String resolvedType,            int flags, int userId) {        if (!sUserManager.exists(userId)) return null;        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");        List query = queryIntentActivities(intent, resolvedType, flags, userId);        return chooseBestActivity(intent, resolvedType, flags, query, userId);}@Override    public List queryIntentActivities(Intent intent,                                                   String resolvedType, int flags, int userId) {        // 获取ComponentName对象,如果该对象不为null,则表明intent指明了ComponentName        ComponentName comp = intent.getComponent();        if (comp == null) {            if (intent.getSelector() != null) {                intent = intent.getSelector();                comp = intent.getComponent();            }        }        if (comp != null) {            final List list = new ArrayList(1);            // 根据comp获取精确的ActivityInfo            final ActivityInfo ai = getActivityInfo(comp, flags, userId);            if (ai != null) {                final ResolveInfo ri = new ResolveInfo();                ri.activityInfo = ai;                list.add(ri);            }            if (homeIntentRestrictedByDPM) {                return getCurrentDefaultHome(list, userId);            }            return list;        }        // reader        synchronized (mPackages) {            final String pkgName = intent.getPackage();            if (pkgName == null) {                // Check for results in the current profile.                List result = mActivities.queryIntent(                        intent, resolvedType, flags, userId);                ....                return result;            }            // 通过包名获取Package对象            final PackageParser.Package pkg = mPackages.get(pkgName);            if (pkg != null) {                // 通过Package对象获取ActivityInfo                List result = mActivities.queryIntentForPackage(                        intent, resolvedType, flags, pkg.activities, userId);                if (homeIntentRestrictedByDPM) {                    return getCurrentDefaultHome(result, userId);                }                return filterIfNotPrimaryUser(result, userId);            }            return new ArrayList();        }}

上面方法中,当intent指明了Componet,那么直接通过ComponentName就可以找到一个ActivityInfo列表,并且该列表只有一个,如果没有指定,那么先查看Intent是否制定了需要跳转到对应的包,如果有包名,则通过包名获取对应的ActivityInfo.

到此为止,apk信息的构建以及intent的匹配就完成了。

更多相关文章

  1. Android文件系统的提取方法(一)
  2. Android样式化的定型对象 — Style样式的定义
  3. Android发送邮件附带文件
  4. android的文件系统结构及其引导过程的初步理解
  5. Android获取webView快照与屏幕截屏的方法
  6. Android测量View宽和高的一般通用方法

随机推荐

  1. 使用saripaar对android输入控件进行快速
  2. Android(安卓)uevent
  3. Android用xml写动画效果
  4. android 来电自动接听和自动挂断
  5. Spinner控件的使用
  6. 2010.12.13——— android listView 滚动
  7. Android访问WCF服务(使用json实现参数传
  8. Android消息机制不完全解析(上)
  9. java\tomcat\android\mysql 环境变量
  10. adt20新建项目Android(安卓)Support libr