ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[start-activity]PackageManagerService

2021-07-31 22:34:13  阅读:205  来源: 互联网

标签:PackageManagerService return userId start flags activity intent null final


目录

概述

在launcher中点击应用来启动应用。

启动应用的过程中,用intent通过PMS来查询对应的activity信息,得到ActivityInfo信息和applicationInfo信息

1. 调用流程

PackageManagerInternalImpl类:resolveIntent
	-> PackageManagerService类:queryIntentActivitiesInternal
		-> getActivityInfo
			-> ComponentResolver类:getActivity(最主要是这个了):获得PackageParser.Activity,安装应用的时候,解析所有 Android 组件类型 [活动、服务、提供者和接收者]
			->  Settings类:mSettings.mPackages.get(component.getPackageName()):包名到packageSetting的映射,PackageSetting中有包的安装位置等信息
			-> PackageParser类:PackageParser.generateActivityInfo:根据PackageParser.Activity信息生成activityInfo
		-> ResolveInfo类:ri.activityInfo = ai;生成ResolveInfo对象并返回
	-> PackageManagerService类:chooseBestActivity:在list<ResolveInfo>中挑一个最匹配的

源码解析

framework层

1. [PMS内部类]PackageManagerInternalImpl类

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

PackageManagerInternal抽象类的实现,PackageManager的接口实现,PMS对外接口实现

1.1 resolveIntent-解析intent-获取activity的信息-包的位置-activity的名字等-ActivityInfo信息

        @Override
        public ResolveInfo resolveIntent(Intent intent, String resolvedType,
                int flags, int userId, boolean resolveForStart, int filterCallingUid) {
            return resolveIntentInternal(
                    intent, resolvedType, flags, userId, resolveForStart, filterCallingUid);
        }

1.2 resolveIntentInternal-解析intent信息

// intent:Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 pkg=com.android.gallery3d cmp=com.android.gallery3d/.app.GalleryActivity bnds=[350,426][460,552] }
// resolvedType为null;flags为66560;userId为0;resolveForStart为true;filterCallingUid为10081就是Launcher应用
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
            int flags, int userId, boolean resolveForStart, int filterCallingUid) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");

            if (!sUserManager.exists(userId)) return null;// user 0肯定是存在的
            final int callingUid = Binder.getCallingUid();	// system用户
            // 更新flags,和instant app和direct app有关;更新后为852992
            flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart);
            mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                    false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");

            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
            // 1. 查询安装的应用,看是否有匹配的intent
            final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, filterCallingUid, userId, resolveForStart, true /*allowDynamicSplits*/);
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

            final ResolveInfo bestChoice =
                // 选择最匹配的activity,因为query是个list;但是这里list大小为1,所以直接返回了
                    chooseBestActivity(intent, resolvedType, flags, query, userId);
            return bestChoice;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

2. PackageManagerService类

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

2.1 queryIntentActivitiesInternal-根据intent查询activity的信息

    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
            String resolvedType, int flags, int filterCallingUid, int userId,
            boolean resolveForStart, boolean allowDynamicSplits) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);	//为null
        mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                false /* requireFullPermission */, false /* checkShell */,
                "query intent activities");
        final String pkgName = intent.getPackage();// com.android.gallery3d
        ComponentName comp = intent.getComponent();// ComponentInfo{com.android.gallery3d/com.android.gallery3d.app.GalleryActivity}
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
                comp = intent.getComponent();
            }
        }

        flags = updateFlagsForResolve(flags, userId, intent, filterCallingUid, resolveForStart,
                comp != null || pkgName != null /*onlyExposedExplicitly*/);// 852992
        if (comp != null) {
            final List<ResolveInfo> list = new ArrayList<>(1);
            // 1. 这里获取activityInfo信息
            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
            if (ai != null) {
                // When specifying an explicit component, we prevent the activity from being
                // used when either 1) the calling package is normal and the activity is within
                // an ephemeral application or 2) the calling package is ephemeral and the
                // activity is not visible to ephemeral applications.
                final boolean matchInstantApp =
                        (flags & PackageManager.MATCH_INSTANT) != 0;
                final boolean matchVisibleToInstantAppOnly =
                        (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
                final boolean matchExplicitlyVisibleOnly =
                        (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
                final boolean isCallerInstantApp =
                        instantAppPkgName != null;
                final boolean isTargetSameInstantApp =
                        comp.getPackageName().equals(instantAppPkgName);
                final boolean isTargetInstantApp =
                        (ai.applicationInfo.privateFlags
                                & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
                final boolean isTargetVisibleToInstantApp =
                        (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
                final boolean isTargetExplicitlyVisibleToInstantApp =
                        isTargetVisibleToInstantApp
                        && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
                final boolean isTargetHiddenFromInstantApp =
                        !isTargetVisibleToInstantApp
                        || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp);
                final boolean blockResolution =
                        !isTargetSameInstantApp
                        && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
                                || (matchVisibleToInstantAppOnly && isCallerInstantApp
                                        && isTargetHiddenFromInstantApp));
                if (!blockResolution) {
                    final ResolveInfo ri = new ResolveInfo();
                    // 根据activityInfo信息,新建了ResolveInfo信息
                    ri.activityInfo = ai;
                    list.add(ri);
                }
            }// 过滤resolveInfo信息,在这里直接返回了
            return applyPostResolutionFilter(
                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                    userId, intent);
        }
// 当cmp不为null的时候,不走下面
        // reader
        boolean sortResult = false;
        boolean addInstant = false;
        List<ResolveInfo> result;
        synchronized (mPackages) {
            if (pkgName == null) {
                List<CrossProfileIntentFilter> matchingFilters =
                        getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
                // Check for results that need to skip the current profile.
                ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                        resolvedType, flags, userId);
                if (xpResolveInfo != null) {
                    List<ResolveInfo> xpResult = new ArrayList<>(1);
                    xpResult.add(xpResolveInfo);
                    return applyPostResolutionFilter(
                            filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
                            allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
                }

                // Check for results in the current profile.
                result = filterIfNotSystemUser(mComponentResolver.queryActivities(
                        intent, resolvedType, flags, userId), userId);
                addInstant = isInstantAppResolutionAllowed(intent, result, userId,
                        false /*skipPackageCheck*/);
                // Check for cross profile results.
                boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                xpResolveInfo = queryCrossProfileIntents(
                        matchingFilters, intent, resolvedType, flags, userId,
                        hasNonNegativePriorityResult);
                if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
                    boolean isVisibleToUser = filterIfNotSystemUser(
                            Collections.singletonList(xpResolveInfo), userId).size() > 0;
                    if (isVisibleToUser) {
                        result.add(xpResolveInfo);
                        sortResult = true;
                    }
                }
                if (intent.hasWebURI()) {
                    CrossProfileDomainInfo xpDomainInfo = null;
                    final UserInfo parent = getProfileParent(userId);
                    if (parent != null) {
                        xpDomainInfo = getCrossProfileDomainPreferredLpr(intent, resolvedType,
                                flags, userId, parent.id);
                    }
                    if (xpDomainInfo != null) {
                        if (xpResolveInfo != null) {
                            // If we didn't remove it, the cross-profile ResolveInfo would be twice
                            // in the result.
                            result.remove(xpResolveInfo);
                        }
                        if (result.size() == 0 && !addInstant) {
                            // No result in current profile, but found candidate in parent user.
                            // And we are not going to add emphemeral app, so we can return the
                            // result straight away.
                            result.add(xpDomainInfo.resolveInfo);
                            return applyPostResolutionFilter(result, instantAppPkgName,
                                    allowDynamicSplits, filterCallingUid, resolveForStart, userId,
                                    intent);
                        }
                    } else if (result.size() <= 1 && !addInstant) {
                        // No result in parent user and <= 1 result in current profile, and we
                        // are not going to add emphemeral app, so we can return the result without
                        // further processing.
                        return applyPostResolutionFilter(result, instantAppPkgName,
                                allowDynamicSplits, filterCallingUid, resolveForStart, userId,
                                intent);
                    }
                    // We have more than one candidate (combining results from current and parent
                    // profile), so we need filtering and sorting.
                    result = filterCandidatesWithDomainPreferredActivitiesLPr(
                            intent, flags, result, xpDomainInfo, userId);
                    sortResult = true;
                }
            } else {
                final PackageParser.Package pkg = mPackages.get(pkgName);
                result = null;
                if (pkg != null) {
                    result = filterIfNotSystemUser(mComponentResolver.queryActivities(
                            intent, resolvedType, flags, pkg.activities, userId), userId);
                }
                if (result == null || result.size() == 0) {
                    // the caller wants to resolve for a particular package; however, there
                    // were no installed results, so, try to find an ephemeral result
                    addInstant = isInstantAppResolutionAllowed(
                                    intent, null /*result*/, userId, true /*skipPackageCheck*/);
                    if (result == null) {
                        result = new ArrayList<>();
                    }
                }
            }
        }
        if (addInstant) {
            result = maybeAddInstantAppInstaller(
                    result, intent, resolvedType, flags, userId, resolveForStart);
        }
        if (sortResult) {
            Collections.sort(result, RESOLVE_PRIORITY_SORTER);
        }
        return applyPostResolutionFilter(
                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
                userId, intent);
    }

2.2 getActivityInfo-获取activityInfo信息

    @Override
    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
        return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
    }
    private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
            int filterCallingUid, int userId) {
        if (!sUserManager.exists(userId)) return null;
        flags = updateFlagsForComponent(flags, userId, component);

        if (!isRecentsAccessingChildProfiles(Binder.getCallingUid(), userId)) {
            mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                    false /* requireFullPermission */, false /* checkShell */, "get activity info");
        }

        synchronized (mPackages) {
            // 所有的安装包信息都解析到mComponentResolver中了,只要获取下就好了
            // 1. Activity{e6ed46 com.android.gallery3d/.app.GalleryActivity}
            PackageParser.Activity a = mComponentResolver.getActivity(component);

            if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
            // 2. 看是否匹配
            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                // 3. PackageSetting很重要,包的位置信息;
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                    return null;
                }// 4. 根据PackageParser.Activity的信息构建ActivityInfo信息,这里返回
                return PackageParser.generateActivityInfo(
                        a, flags, ps.readUserState(userId), userId);
            }
            if (mResolveComponentName.equals(component)) {
                return PackageParser.generateActivityInfo(
                        mResolveActivity, flags, new PackageUserState(), userId);
            }
        }
        return null;
    }

3. ComponentResolver类

frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java

解析所有 Android 组件类型 [活动、服务、提供者和接收者]

3.1 getActivity-根据component名字获取activityinfo信息

    PackageParser.Activity getActivity(ComponentName component) {
        synchronized (mLock) {
            // ActivityIntentResolver类型中的mActivities
            // private final ArrayMap<ComponentName, PackageParser.Activity> mActivities = new ArrayMap<>();
            // 系统中所有的activity都在这里了
            return mActivities.mActivities.get(component);
        }
    }

4. Settings类

frameworks/base/services/core/java/com/android/server/pm/Settings.java

保存PMS有关动态设置的信息
    // 包名到packageSetting的映射,PackageSetting中有包的安装位置等信息
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();

4.1 isEnabledAndMatchLPr

    boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
        final PackageSetting ps = mPackages.get(componentInfo.packageName);
        if (ps == null) return false;

        final PackageUserState userState = ps.readUserState(userId);
        // 是否匹配
        return userState.isMatch(componentInfo, flags);
    }

5. PackageSetting类

./frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java

特定包的设置数据,如代码路径,res路径,pkgFlags等
(1)pkg	PackageParser类,里面有activities,保存activity信息,里面有className,可以加载java class
(2)codePath,可以知道代码的路径信息

应用接口层

1. ResolveInfo类

frameworks/base/core/java/android/content/pm/ResolveInfo.java

对应AndroidManifest.xml's中intent标签中的内容,活动、服务、提供者和接收者的信息。
(1)ActivityInfo
(2)ServiceInfo

2. PackageParser类

frameworks/base/core/java/android/content/pm/PackageParser.java

hide类,应用不可见;用来解析磁盘上的APK文件的;
有很多的内部类:Activity,Service,Provider,Instrumentation,IntentInfo,ActivityIntentInfo等

2.1 generateActivityInfo-根据PackageParser.Activity的信息构建ActivityInfo信息

    @UnsupportedAppUsage
    public static final ActivityInfo generateActivityInfo(Activity a, int flags,
            PackageUserState state, int userId) {
        if (a == null) return null;
        if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
            return null;
        }
        if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
            updateApplicationInfo(a.info.applicationInfo, flags, state);
            return a.info;
        }
        // Make shallow copies so we can store the metadata safely
        ActivityInfo ai = new ActivityInfo(a.info);
        ai.metaData = a.metaData;
        ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
        return ai;
    }

3. ActivityInfo类

./frameworks/base/core/java/android/content/pm/ActivityInfo.java

对应AndroidManifest.xml的activity和receiver的标签

补充

1. Android分层

应用层
应用层接口(一般在frameworks/base/core/java/android/目录下;在developer.android.com网站中有对应手册的,都是应用层接口)
framework服务层(一般在frameworks/base/services/core/java/com/android/server/目录下)
framework层的JNI层和应用层接口的JNI层
native服务层(c/c++层)
hal层
系统调用层
kernel层

问题

1. 各个类有啥用?


PackageSetting

2. PMS怎么找到activity的class的,然后加载起来

3. AndroidManifest.xml是怎么解析的?APK是怎么解析的?对应哪些类-start PMS中-或者安装应用中解析

参考

标签:PackageManagerService,return,userId,start,flags,activity,intent,null,final
来源: https://www.cnblogs.com/pyjetson/p/15085449.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有