Android 7.1設置默認Launcher重啓後失效(需手動選擇)

平臺

RK3288 + Android 7.1

問題描述

安裝Launcher應用, 並設置爲默認主界面, 關機重啓後, 無法默認, 仍然彈出選擇框.

分析

LOG

//開機後啓動的第一個HOME, 是FallbackHome
2019-11-22 15:11:25.542 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0
2019-11-22 15:11:25.565 system_process I/ActivityManager: Start proc 650:com.android.settings/1000 for activity com.android.settings/.FallbackHome
2019-11-22 15:11:26.158 system_process I/ActivityManager: Displayed com.android.settings/.FallbackHome: +604ms
//...
2019-11-22 15:11:27.976 system_process D/ActivityManager: Sending BOOT_COMPLETE user #0
//...
2019-11-22 15:11:28.007 system_process V/PackageManager: Looking for presistent preferred activities...
2019-11-22 15:11:28.007 system_process V/PackageManager: Looking for preferred activities...
2019-11-22 15:11:28.007 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 }
2019-11-22 15:11:28.007 system_process V/IntentResolver: Action list: [PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher}, null]
2019-11-22 15:11:28.008 system_process V/IntentResolver: Matching against filter PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher}
2019-11-22 15:11:28.008 system_process V/IntentResolver:   Filter matched!  match=0x108000 hasDefault=true
2019-11-22 15:11:28.008 system_process V/IntentResolver:     a4a6978 com.teslacoilsw.launcher/.NovaLauncher
2019-11-22 15:11:28.008 system_process V/IntentResolver:      mMatch=0x100000 mAlways=true
2019-11-22 15:11:28.008 system_process V/IntentResolver:       Selected from:
2019-11-22 15:11:28.008 system_process V/IntentResolver:         com.android.launcher3/.Launcher
2019-11-22 15:11:28.008 system_process V/IntentResolver:         com.teslacoilsw.launcher/.NovaLauncher
2019-11-22 15:11:28.008 system_process V/IntentResolver:         com.android.settings/.FallbackHome
2019-11-22 15:11:28.008 system_process V/IntentResolver:     Action: "android.intent.action.MAIN"
2019-11-22 15:11:28.008 system_process V/IntentResolver:     Category: "android.intent.category.HOME"
2019-11-22 15:11:28.008 system_process V/IntentResolver:     Category: "android.intent.category.DEFAULT"
2019-11-22 15:11:28.008 system_process V/IntentResolver:     AutoVerify=false
2019-11-22 15:11:28.008 system_process V/IntentResolver: Final result list:
2019-11-22 15:11:28.008 system_process V/IntentResolver:   PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher}
2019-11-22 15:11:28.008 system_process V/PackageManager: Figuring out best match...
2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0
2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000
2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000
2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000
2019-11-22 15:11:28.011 system_process V/PackageManager: Best match: 0x108000
2019-11-22 15:11:28.011 system_process V/PackageManager: Checking PreferredActivity ds=<none>
      component=ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher}
2019-11-22 15:11:28.011 system_process V/PackageManager:   Action: "android.intent.action.MAIN"
2019-11-22 15:11:28.011 system_process V/PackageManager:   Category: "android.intent.category.HOME"
2019-11-22 15:11:28.011 system_process V/PackageManager:   Category: "android.intent.category.DEFAULT"
2019-11-22 15:11:28.011 system_process V/PackageManager:   AutoVerify=false
2019-11-22 15:11:28.011 system_process V/PackageManager: Found preferred activity:
2019-11-22 15:11:28.011 system_process V/PackageManager:   name=com.teslacoilsw.launcher.NovaLauncher
2019-11-22 15:11:28.011 system_process V/PackageManager:   packageName=com.teslacoilsw.launcher
2019-11-22 15:11:28.011 system_process V/PackageManager:   enabled=true exported=true directBootAware=false
2019-11-22 15:11:28.011 system_process V/PackageManager:   taskAffinity=com.teslacoilsw.launcher.NovaLauncher targetActivity=null persistableMode=PERSIST_ROOT_ONLY
2019-11-22 15:11:28.011 system_process V/PackageManager:   launchMode=3 flags=0x3 theme=0x7f0d00f2
2019-11-22 15:11:28.011 system_process V/PackageManager:   screenOrientation=5 configChanges=0x203 softInputMode=0x20
2019-11-22 15:11:28.011 system_process V/PackageManager:   lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT
2019-11-22 15:11:28.011 system_process V/PackageManager:   resizeMode=RESIZE_MODE_RESIZEABLE
2019-11-22 15:11:28.011 system_process V/PackageManager:   ApplicationInfo:
2019-11-22 15:11:28.011 system_process V/PackageManager:     name=com.android.launcher3.LauncherApplication
2019-11-22 15:11:28.011 system_process V/PackageManager:     packageName=com.teslacoilsw.launcher
2019-11-22 15:11:28.011 system_process V/PackageManager:     labelRes=0x7f0a0060 nonLocalizedLabel=null icon=0x7f030008 banner=0x0
2019-11-22 15:11:28.011 system_process V/PackageManager:     className=com.android.launcher3.LauncherApplication
2019-11-22 15:11:28.011 system_process V/PackageManager:     processName=com.teslacoilsw.launcher
2019-11-22 15:11:28.011 system_process V/PackageManager:     taskAffinity=com.teslacoilsw.launcher
2019-11-22 15:11:28.011 system_process V/PackageManager:     uid=10054 flags=0x3 privateFlags=0x800 theme=0x0
2019-11-22 15:11:28.011 system_process V/PackageManager:     requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0
2019-11-22 15:11:28.012 system_process V/PackageManager:     sourceDir=/data/app/com.teslacoilsw.launcher-1/base.apk
2019-11-22 15:11:28.012 system_process V/PackageManager:     seinfo=default
2019-11-22 15:11:28.012 system_process V/PackageManager:     dataDir=/data/user/0/com.teslacoilsw.launcher
2019-11-22 15:11:28.012 system_process V/PackageManager:     deviceProtectedDataDir=/data/user_de/0/com.teslacoilsw.launcher
2019-11-22 15:11:28.012 system_process V/PackageManager:     credentialProtectedDataDir=/data/user/0/com.teslacoilsw.launcher
2019-11-22 15:11:28.012 system_process V/PackageManager:     enabled=true minSdkVersion=16 targetSdkVersion=25 versionCode=50102
2019-11-22 15:11:28.012 system_process V/PackageManager:     supportsRtl=true
2019-11-22 15:11:28.012 system_process V/PackageManager:     fullBackupContent=true

//關鍵LOG, 這裏把默認信息刪除了.
2019-11-22 15:11:28.012 system_process I/PackageManager: Result set changed, dropping preferred activity for Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 } type null
2019-11-22 15:11:28.012 system_process V/PackageManager: Removing preferred activity since set changed ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher}
2019-11-22 15:11:28.012 system_process V/PackageManager: Preferred activity bookkeeping changed; writing restrictions
2019-11-22 15:11:28.013 com.android.settings D/FallbackHome: User unlocked and real home found; let's go!

//再一次查找HOME時, 發現沒有了默認信息, 所以顯示了選擇提示框
2019-11-22 15:11:28.049 system_process I/AccountManagerService: User 0 is unlocked - opening CE database
2019-11-22 15:11:28.056 system_process V/PackageManager: Looking for presistent preferred activities...
2019-11-22 15:11:28.056 system_process V/PackageManager: Looking for preferred activities...
2019-11-22 15:11:28.057 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x108 }
2019-11-22 15:11:28.057 system_process V/IntentResolver: Action list: [PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher}, null]
2019-11-22 15:11:28.057 system_process V/IntentResolver: Matching against filter PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher}
2019-11-22 15:11:28.057 system_process V/IntentResolver:   Filter matched!  match=0x108000 hasDefault=true
2019-11-22 15:11:28.057 system_process V/IntentResolver:     f98a6ce com.teslacoilsw.launcher/.NovaLauncher
2019-11-22 15:11:28.057 system_process V/IntentResolver:      mMatch=0x100000 mAlways=false
2019-11-22 15:11:28.057 system_process V/IntentResolver:     Action: "android.intent.action.MAIN"
2019-11-22 15:11:28.057 system_process V/IntentResolver:     Category: "android.intent.category.HOME"
2019-11-22 15:11:28.057 system_process V/IntentResolver:     Category: "android.intent.category.DEFAULT"
2019-11-22 15:11:28.057 system_process V/IntentResolver:     AutoVerify=false
2019-11-22 15:11:28.057 system_process V/IntentResolver: Final result list:
2019-11-22 15:11:28.057 system_process V/IntentResolver:   PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher}
2019-11-22 15:11:28.057 system_process V/PackageManager: Figuring out best match...
2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0
2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000
2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000
2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000
2019-11-22 15:11:28.057 system_process V/PackageManager: Best match: 0x108000
2019-11-22 15:11:28.057 system_process V/PackageManager: Checking PreferredActivity ds=<none>
      component=ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher}
2019-11-22 15:11:28.057 system_process V/PackageManager:   Action: "android.intent.action.MAIN"
2019-11-22 15:11:28.057 system_process V/PackageManager:   Category: "android.intent.category.HOME"
2019-11-22 15:11:28.057 system_process V/PackageManager:   Category: "android.intent.category.DEFAULT"
2019-11-22 15:11:28.057 system_process V/PackageManager:   AutoVerify=false
2019-11-22 15:11:28.058 system_process V/PackageManager: Skipping mAlways=false entry
2019-11-22 15:11:28.058 system_process V/PackageManager: No preferred activity to return
2019-11-22 15:11:28.058 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000108 cmp=android/com.android.internal.app.ResolverActivity} from uid 0 on display 0
2019-11-22 15:11:28.058 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000108 cmp=android/com.android.internal.app.ResolverActivity }
2019-11-22 15:11:28.058 system_process V/IntentResolver: Action list: null
2019-11-22 15:11:28.058 system_process V/IntentResolver: Final result list:
2019-11-22 15:11:28.090 ? W/System: ClassLoader referenced unknown path: /system/priv-app/StressTest/lib/arm
2019-11-22 15:11:28.098 system_process I/ActivityManager: Start proc 1076:system:ui/1000 for activity android/com.android.internal.app.ResolverActivity
  • 開機, 第一次啓動:
	I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0
  • 開機完成第一次, 在退出FallbackHome後:
	V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 }
	//此時因爲缺少了CATEGORY_DEFAULT, 所以PM在查找時, 會找到四個, 分別是:
	Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0
	Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000
	Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000
	Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000
  • 在選擇默認時保存的是:
	2019-11-23 09:02:38.677 system_process I/PackageManager: Adding preferred activity com.teslacoilsw.launcher/.NovaLauncher for user 0:
	2019-11-23 09:02:38.677 system_process I/PackageManager:   Action: "android.intent.action.MAIN"
	2019-11-23 09:02:38.677 system_process I/PackageManager:   Category: "android.intent.category.HOME"
	2019-11-23 09:02:38.677 system_process I/PackageManager:   Category: "android.intent.category.DEFAULT"
	2019-11-23 09:02:38.677 system_process I/PackageManager:   AutoVerify=false
	2019-11-23 09:02:38.679 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x13000108 cmp=com.teslacoilsw.launcher/.NovaLauncher} from uid 0 on display 0
	2019-11-23 09:02:38.679 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x13000108 cmp=com.teslacoilsw.launcher/.NovaLauncher }
	2019-11-23 09:02:38.679 system_process V/IntentResolver: Action list: null
	2019-11-23 09:02:38.679 system_process V/IntentResolver: Final result list:

相關代碼如下:

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

    @Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId) {
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");

            if (!sUserManager.exists(userId)) return null;
            flags = updateFlagsForResolve(flags, userId, intent);
            enforceCrossUserPermission(Binder.getCallingUid(), userId,
                    false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");

            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
            final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, userId);
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

            final ResolveInfo bestChoice =
                    chooseBestActivity(intent, resolvedType, flags, query, userId);
            return bestChoice;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

    private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
            int flags, List<ResolveInfo> query, int userId) {
        if (query != null) {
            final int N = query.size();
            if (N == 1) {
                return query.get(0);
            } else if (N > 1) {
                final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
                // If there is more than one activity with the same priority,
                // then let the user decide between them.
                ResolveInfo r0 = query.get(0);
                ResolveInfo r1 = query.get(1);
                if (DEBUG_INTENT_MATCHING || debug) {
                    Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
                            + r1.activityInfo.name + "=" + r1.priority);
                }
                // If the first activity has a higher priority, or a different
                // default, then it is always desirable to pick it.
                if (r0.priority != r1.priority
                        || r0.preferredOrder != r1.preferredOrder
                        || r0.isDefault != r1.isDefault) {
                    return query.get(0);
                }
                // If we have saved a preference for a preferred activity for
                // this Intent, use that.
                ResolveInfo ri = findPreferredActivity(intent, resolvedType,
                        flags, query, r0.priority, true, false, debug, userId);
                if (ri != null) {
                    return ri;
                }
                ri = new ResolveInfo(mResolveInfo);
                ri.activityInfo = new ActivityInfo(ri.activityInfo);
                ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction());
                // If all of the options come from the same package, show the application's
                // label and icon instead of the generic resolver's.
                // Some calls like Intent.resolveActivityInfo query the ResolveInfo from here
                // and then throw away the ResolveInfo itself, meaning that the caller loses
                // the resolvePackageName. Therefore the activityInfo.labelRes above provides
                // a fallback for this case; we only set the target package's resources on
                // the ResolveInfo, not the ActivityInfo.
                final String intentPackage = intent.getPackage();
                if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) {
                    final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo;
                    ri.resolvePackageName = intentPackage;
                    if (userNeedsBadging(userId)) {
                        ri.noResourceId = true;
                    } else {
                        ri.icon = appi.icon;
                    }
                    ri.iconResourceId = appi.icon;
                    ri.labelRes = appi.labelRes;
                }
                ri.activityInfo.applicationInfo = new ApplicationInfo(
                        ri.activityInfo.applicationInfo);
                if (userId != 0) {
                    ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId,
                            UserHandle.getAppId(ri.activityInfo.applicationInfo.uid));
                }
                // Make sure that the resolver is displayable in car mode
                if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle();
                ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true);
                return ri;
            }
        }
        return null;
    }

    ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
            List<ResolveInfo> query, int priority, boolean always,
            boolean removeMatches, boolean debug, int userId) {
        if (!sUserManager.exists(userId)) return null;
        flags = updateFlagsForResolve(flags, userId, intent);
        // writer
        synchronized (mPackages) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
            }
            if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);

            // Try to find a matching persistent preferred activity.
            ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
                    debug, userId);

            // If a persistent preferred activity matched, use it.
            if (pri != null) {
                return pri;
            }

            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
            // Get the list of preferred activities that handle the intent
            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
            List<PreferredActivity> prefs = pir != null
                    ? pir.queryIntent(intent, resolvedType,
                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
                    : null;
            if (prefs != null && prefs.size() > 0) {
                boolean changed = false;
                try {
                    // First figure out how good the original match set is.
                    // We will only allow preferred activities that came
                    // from the same match quality.
                    int match = 0;

                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");

                    final int N = query.size();
                    for (int j=0; j<N; j++) {
                        final ResolveInfo ri = query.get(j);
                        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo
                                + ": 0x" + Integer.toHexString(match));
                        if (ri.match > match) {
                            match = ri.match;
                        }
                    }

                    if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x"
                            + Integer.toHexString(match));

                    match &= IntentFilter.MATCH_CATEGORY_MASK;
                    final int M = prefs.size();
                    for (int i=0; i<M; i++) {
                        final PreferredActivity pa = prefs.get(i);
                        if (DEBUG_PREFERRED || debug) {
                            Slog.v(TAG, "Checking PreferredActivity ds="
                                    + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
                                    + "\n  component=" + pa.mPref.mComponent);
                            pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
                        }
                        if (pa.mPref.mMatch != match) {
                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match "
                                    + Integer.toHexString(pa.mPref.mMatch));
                            continue;
                        }
                        // If it's not an "always" type preferred activity and that's what we're
                        // looking for, skip it.
                        if (always && !pa.mPref.mAlways) {
                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
                            continue;
                        }
                        final ActivityInfo ai = getActivityInfo(
                                pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
                                        | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
                                userId);
                        if (DEBUG_PREFERRED || debug) {
                            Slog.v(TAG, "Found preferred activity:");
                            if (ai != null) {
                                ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), "  ");
                            } else {
                                Slog.v(TAG, "  null");
                            }
                        }
                        if (ai == null) {
                            // This previously registered preferred activity
                            // component is no longer known.  Most likely an update
                            // to the app was installed and in the new version this
                            // component no longer exists.  Clean it up by removing
                            // it from the preferred activities list, and skip it.
                            Slog.w(TAG, "Removing dangling preferred activity: "
                                    + pa.mPref.mComponent);
                            pir.removeFilter(pa);
                            changed = true;
                            continue;
                        }
                        for (int j=0; j<N; j++) {
                            final ResolveInfo ri = query.get(j);
                            if (!ri.activityInfo.applicationInfo.packageName
                                    .equals(ai.applicationInfo.packageName)) {
                                continue;
                            }
                            if (!ri.activityInfo.name.equals(ai.name)) {
                                continue;
                            }

                            if (removeMatches) {
                                pir.removeFilter(pa);
                                changed = true;
                                if (DEBUG_PREFERRED) {
                                    Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
                                }
                                break;
                            }

                            // Okay we found a previously set preferred or last chosen app.
                            // If the result set is different from when this
                            // was created, we need to clear it and re-ask the
                            // user their preference, if we're looking for an "always" type entry.
                            if (always && !pa.mPref.sameSet(query)) {
                                Slog.i(TAG, "Result set changed, dropping preferred activity for "
                                        + intent + " type " + resolvedType);
                                if (DEBUG_PREFERRED) {
                                    Slog.v(TAG, "Removing preferred activity since set changed "
                                            + pa.mPref.mComponent);
                                }
                                pir.removeFilter(pa);
                                // Re-add the filter as a "last chosen" entry (!always)
                                PreferredActivity lastChosen = new PreferredActivity(
                                        pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
                                pir.addFilter(lastChosen);
                                changed = true;
                                return null;
                            }

                            // Yay! Either the set matched or we're looking for the last chosen
                            if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: "
                                    + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
                            return ri;
                        }
                    }
                } finally {
                    if (changed) {
                        if (DEBUG_PREFERRED) {
                            Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
                        }
                        scheduleWritePackageRestrictionsLocked(userId);
                    }
                }
            }
        }
        if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
        return null;
    }

原因與解決方案

分解下出問題時的步驟:

  1. 安裝新的Launcher
  2. 點擊HOME鍵, 並從列表中選擇一個默認爲默認
  3. 重啓主板
  4. 主板顯示列表選擇框.
  • 出現問題的地方在第4步

    • 從上面的LOG可以看出, 設置默認時的信息是: act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT]
    • 在重啓後, 過入了FallbackHome, 在FallbackHome有以下代碼調用PM的resolveActivity方法, 而此方法傳入的Intent爲act=android.intent.action.MAIN cat=[android.intent.category.HOME]:
      private void maybeFinish() {
          if (getSystemService(UserManager.class).isUserUnlocked()) {
              final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                      .addCategory(Intent.CATEGORY_HOME);
              final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);
              if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {
                  Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");
                  mHandler.sendEmptyMessageDelayed(0, 200);
              } else {
                  Log.d(TAG, "User unlocked and real home found; let's go!");
                  getSystemService(PowerManager.class).userActivity(
                          SystemClock.uptimeMillis(), false);
                  finish();
              }
          }
      }
    
    • 在FallbackHome執行完後, PM會刪除默認信息: PackageManager: Removing preferred activity since set changed ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher}
    • 刪除默認信息後, 當FallbackHome finish自己後, 系統重新startHome時, 就會出現, 未找到默認, 並顯示列表選擇框
  • 啓動後, 第一個進入的Launcher是 Settings中的 FallbackHome, 在啓動初始化完成後, FallbackHome會Finsish自己, 並交由系統去啓動新的Launcher.
    問題出現時, 在PM中查找Launcher的數量與之前設置默認時不一致:

    • 第一次是4個:
    {ActivityInfo{da70dd6 com.android.launcher3.Launcher}}
    {ActivityInfo{fdc4857 com.teslacoilsw.launcher.NovaLauncher}}
    {ActivityInfo{91f7f44 teaonly.rk.droidipcam.CameraActivity}}
    {ActivityInfo{6138c45 com.android.settings.FallbackHome}}
    
  • 在後面選擇了默認後, 是3個:
    {ActivityInfo{da70dd6 com.android.launcher3.Launcher}}
    {ActivityInfo{fdc4857 com.teslacoilsw.launcher.NovaLauncher}}
    {ActivityInfo{6138c45 com.android.settings.FallbackHome}}
    
    • 多出來的一個 CameraActivity定義如下(缺少了category.DEFAULT):
        <activity
            android:name="teaonly.rk.droidipcam.CameraActivity"
            android:label="@string/app_name"
            android:screenOrientation="landscape" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
  • 之所有會出現數量上的差別, 是由於在調用PM的resolveIntent遍歷時, 有兩個相關的因素:
    • 傳去的FLAG不同: PackageManager.MATCH_DEFAULT_ONLY(0x00010000)
    • Intent中帶的信息不同.

解決方案:

1

1.1 修改 FallbackHome 的 maybeFinish函數

    private void maybeFinish() {
        if (getSystemService(UserManager.class).isUserUnlocked()) {
            final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_HOME).
//添加DEFAULT使Intent保持與保存默認的信息一致
					.addCategory(Intent.CATEGORY_DEFAULT);
            //...
        }
    }

1.2 同樣修改 FallbackHome 的 maybeFinish函數

    private void maybeFinish() {
        //...
//0 -> android.content.pm.PackageManager.MATCH_DEFAULT_ONLY
            final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY);
       //...
    }
  • PS 1/2 的方法需配合修改:
    |–frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
//添加DEFAULT
			intent.addCategory(Intent.CATEGORY_DEFAULT);
        }
        return intent;
    }

2

在PM中強制爲Launcher的過濾添加 DEFAULT

--- a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4830,6 +4830,14 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
     }
 
+       //AnsonCode
+       boolean isHome(Intent intent){
+               if(intent != null && intent.getCategories() != null){
+                               return intent.getAction().equals(Intent.ACTION_MAIN) && intent.getCategories().contains(Intent.CATEGORY_HOME);
+               }
+               return false;
+       }
+
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
@@ -4842,6 +4850,10 @@ public class PackageManagerService extends IPackageManager.Stub {
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
 
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
+                       //AnsonCode
+                       if(isHome(intent)){
+                               flags |= PackageManager.MATCH_DEFAULT_ONLY;
+                       }
             final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                     flags, userId);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

擴展

  • FallbackHome 與 Launcher

    • FallbackHome的註冊信息:
    		<activity android:name=".FallbackHome"
    				  android:excludeFromRecents="true"
    				  android:screenOrientation="nosensor"
    				  android:theme="@style/FallbackHome">
    			<intent-filter android:priority="-1000">
    				<action android:name="android.intent.action.MAIN" />
    				<category android:name="android.intent.category.HOME" />
    				<category android:name="android.intent.category.DEFAULT" />
    			</intent-filter>
    		</activity>
    
    • Launcher的註冊信息:
        <activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/LauncherTheme"
            android:windowSoftInputMode="adjustPan"
            android:configChanges="keyboard|keyboardHidden|navigation"
            android:resumeWhilePausing="true"
            android:taskAffinity=""
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
            </intent-filter>
        </activity>
    
    
    • 啓動的順序:
    2019-11-22 14:55:32.453 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0
    2019-11-22 14:55:35.073 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0 on display 0
    

    首先, FallbackHome的優先級是比較低的, 但反而是先於launcher啓動, 主要是由於Settings中有 android:directBootAware="true"的定義,
    參見android 7.1 缺少設置directBootAware導致無法啓動指定Launcher

  • 偏好activity儲存位置: ./system/users/0/package-restrictions.xml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章