频道栏目
首页 > 资讯 > 其他 > 正文

Intent的匹配与查找

16-11-15        来源:[db:作者]  
收藏   我要投稿

PMS解析已安装的apk信息

我们知道系统在启动的时候会加载系统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<n; 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)" (r="=" null)="" r="new" stringbuilder(256);="" }="" else="" r.append('="" ');="" r.append(s.info.name);="" (debug_package_scanning)="" log.d(tag,="" "="" services:="" +="" r);="" n="pkg.receivers.size();" for="" (i="0;" i="" <="" pre="">

将之前保存在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

@Override
public 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的匹配就完成了。

相关TAG标签
上一篇:OpenGL ES 帧缓冲对象(FBO):Render to texture
下一篇:Android启动过程详解(3)——Zygote
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站