Android 哪些系统应用没法禁用(即哪些应用的禁用按钮是灰选)?

好久不见 / 2025-05-01 / 原文

环境:Android S 12 源码

frameworks/base/packages/SettingsLib/src/com/android/settingslib/Utils.java

 /**
     * Determine whether a package is a "system package", in which case certain things (like
     * disabling notifications or disabling the package altogether) should be disallowed.
     */
    public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
        if (sSystemSignature == null) {
            sSystemSignature = new Signature[]{getSystemSignature(pm)};
        }
        if (sPermissionControllerPackageName == null) {
            sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
        }
        if (sServicesSystemSharedLibPackageName == null) {
            sServicesSystemSharedLibPackageName = pm.getServicesSystemSharedLibraryPackageName();
        }
        if (sSharedSystemSharedLibPackageName == null) {
            sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
        }
        return (sSystemSignature[0] != null
                && sSystemSignature[0].equals(getFirstSignature(pkg)))
                || pkg.packageName.equals(sPermissionControllerPackageName)
                || pkg.packageName.equals(sServicesSystemSharedLibPackageName)
                || pkg.packageName.equals(sSharedSystemSharedLibPackageName)
                || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
                || isDeviceProvisioningPackage(resources, pkg.packageName);
    }

    private static Signature getFirstSignature(PackageInfo pkg) {
        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
            return pkg.signatures[0];
        }
        return null;
    }

    private static Signature getSystemSignature(PackageManager pm) {
        try {
            final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
            return getFirstSignature(sys);
        } catch (NameNotFoundException e) {
        }
        return null;
    }

    /**
     * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
     * returns {@code false}.
     */
    public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) {
        String deviceProvisioningPackage = resources.getString(
                com.android.internal.R.string.config_deviceProvisioningPackage);
        return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
    }

case1:与"android"包对比签名信息

private static Signature getSystemSignature(PackageManager pm) {
    try {
        final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
        return getFirstSignature(sys);
    } catch (NameNotFoundException e) {
    }
    return null;
}

case2:pm.getPermissionControllerPackageName()

PackageManagerService.java

@Override
    public String getPermissionControllerPackageName() {
        synchronized (mLock) {
            if (mRequiredPermissionControllerPackage != null) {
                final PackageSetting ps = getPackageSetting(mRequiredPermissionControllerPackage);
                if (ps != null) {
                    final int callingUid = Binder.getCallingUid();
                    final int callingUserId = UserHandle.getUserId(callingUid);
                    if (!shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
                        return mRequiredPermissionControllerPackage;
                    }
                }
            }
            throw new IllegalStateException("PermissionController is not found");
        }
    }

mRequiredPermissionControllerPackage 变量由下面方法赋值

private @NonNull String getRequiredPermissionControllerLPr() {
        final Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSIONS);
        intent.addCategory(Intent.CATEGORY_DEFAULT);

        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
                UserHandle.USER_SYSTEM);
        if (matches.size() == 1) {
            ResolveInfo resolveInfo = matches.get(0);
            if (!resolveInfo.activityInfo.applicationInfo.isPrivilegedApp()) {
                throw new RuntimeException("The permissions manager must be a privileged app");
            }
            return matches.get(0).getComponentInfo().packageName;
        } else {
            throw new RuntimeException("There must be exactly one permissions manager; found "
                    + matches);
        }
    }

public static final String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";

示例:mainline包的permissioncontroller (com.google.android.permissioncontroller) 默认是无法被禁用的,即按钮默认是灰选的

反编译 permissioncontroller  

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="301501400" android:versionName="r_aml_301501400" android:compileSdkVersion="30" android:compileSdkVersionCodename="11" coreApp="true" package="com.google.android.permissioncontroller" platformBuildVersionCode="30" platformBuildVersionName="11">


<application android:theme="@style/FilterTouches" android:label="@string/app_name" android:icon="@drawable/ic_permission_controller_app_icon" android:name="com.android.permissioncontroller.PermissionControllerApplication" android:allowClearUserData="false" android:allowBackup="false" android:supportsRtl="true" android:extractNativeLibs="false" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:forceQueryable="true">


       <activity android:theme="@style/Settings_FilterTouches" android:label="@string/app_permissions" android:name="com.android.permissioncontroller.permission.ui.ManagePermissionsActivity" android:permission="android.permission.GRANT_RUNTIME_PERMISSIONS" android:configChanges="keyboardHidden|orientation|screenSize">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.MANAGE_APP_PERMISSIONS"/>
                <action android:name="android.intent.action.MANAGE_APP_PERMISSION"/>
                <action android:name="android.intent.action.MANAGE_PERMISSION_APPS"/>
                <action android:name="android.intent.action.MANAGE_PERMISSIONS"/>
                <action android:name="android.intent.action.REVIEW_PERMISSION_USAGE"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

application标签存在 directBootAware 属性,能够匹配 上面的 queryIntentActivitiesInternal 方法。

case3:pm.getServicesSystemSharedLibraryPackageName()

    @Override
    public @NonNull String getServicesSystemSharedLibraryPackageName() {
        // allow instant applications
        synchronized (mLock) {
            return mServicesExtensionPackageName;
        }
    }
......
    
    mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
......
    @NonNull
    private String getRequiredServicesExtensionPackageLPr() {
        String servicesExtensionPackage =
                ensureSystemPackageName(
                        mContext.getString(R.string.config_servicesExtensionPackage));
        if (TextUtils.isEmpty(servicesExtensionPackage)) {
            throw new RuntimeException(
                    "Required services extension package is missing, check "
                            + "config_servicesExtensionPackage.");
        }
        return servicesExtensionPackage;
    }
......
    frameworks/base/core/res/res/values/config.xml
    <!-- Package name of the required service extension package. -->
    <string name="config_servicesExtensionPackage" translatable="false">android.ext.services</string>
......
     @Nullable
    private String ensureSystemPackageName(@Nullable String packageName) {
        if (packageName == null) {
            return null;
        }
        final long token = Binder.clearCallingIdentity();
        try {
            if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
                PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
                if (packageInfo != null) {
                    EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
                            "");
                }
                return null;
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
        return packageName;
    }

case4:pm.getSharedSystemSharedLibraryPackageName()

    @Override
    public @NonNull String getSharedSystemSharedLibraryPackageName() {
        // allow instant applications
        synchronized (mLock) {
            return mSharedSystemSharedLibraryPackageName;
        }
    }
......
    mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
                        SharedLibraryInfo.VERSION_UNDEFINED);
......
    public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";

示例:GMS包的GoogleExtShared.apk (com.google.android.ext.shared) 默认是无法被禁用的,即按钮默认是灰选的

反编译 GoogleExtShared.apk 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1" android:compileSdkVersion="30" android:compileSdkVersionCodename="11" coreApp="true" package="com.google.android.ext.shared" platformBuildVersionCode="30" platformBuildVersionName="11">
    <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30"/>
    <application android:label="@string/app_name" android:allowBackup="false" android:extractNativeLibs="true" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true">
        <library android:name="android.ext.shared"/>
    </application>
</manifest>

(Partner-Facing) Google Product Geo-Availability Chart on Android v3 (MADA Partners)(1).xlsx