diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 6fefbf980dc59..081f3f6737021 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -16,6 +16,7 @@ package com.android.providers.settings; +import static android.os.Process.INVALID_UID; import static android.os.Process.ROOT_UID; import static android.os.Process.SHELL_UID; import static android.os.Process.SYSTEM_UID; @@ -363,11 +364,6 @@ public class SettingsProvider extends ContentProvider { mHandler = new Handler(mHandlerThread.getLooper()); mSettingsRegistry = new SettingsRegistry(); } - SettingsState.cacheSystemPackageNamesAndSystemSignature(getContext()); - synchronized (mLock) { - mSettingsRegistry.migrateAllLegacySettingsIfNeededLocked(); - mSettingsRegistry.syncSsaidTableOnStartLocked(); - } mHandler.post(() -> { registerBroadcastReceivers(); startWatchingUserRestrictionChanges(); @@ -2500,6 +2496,8 @@ public class SettingsProvider extends ContentProvider { mHandler = new MyHandler(getContext().getMainLooper()); mGenerationRegistry = new GenerationRegistry(mLock); mBackupManager = new BackupManager(getContext()); + migrateAllLegacySettingsIfNeeded(); + syncSsaidTableOnStart(); } private void generateUserKeyLocked(int userId) { @@ -2586,36 +2584,38 @@ public class SettingsProvider extends ContentProvider { return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid); } - private void syncSsaidTableOnStartLocked() { - // Verify that each user's packages and ssaid's are in sync. - for (UserInfo user : mUserManager.getAliveUsers()) { - // Get all uids for the user's packages. - final List packages; - try { - packages = mPackageManager.getInstalledPackages( + public void syncSsaidTableOnStart() { + synchronized (mLock) { + // Verify that each user's packages and ssaid's are in sync. + for (UserInfo user : mUserManager.getAliveUsers()) { + // Get all uids for the user's packages. + final List packages; + try { + packages = mPackageManager.getInstalledPackages( PackageManager.MATCH_UNINSTALLED_PACKAGES, user.id).getList(); - } catch (RemoteException e) { - throw new IllegalStateException("Package manager not available"); - } - final Set appUids = new HashSet<>(); - for (PackageInfo info : packages) { - appUids.add(Integer.toString(info.applicationInfo.uid)); - } + } catch (RemoteException e) { + throw new IllegalStateException("Package manager not available"); + } + final Set appUids = new HashSet<>(); + for (PackageInfo info : packages) { + appUids.add(Integer.toString(info.applicationInfo.uid)); + } - // Get all uids currently stored in the user's ssaid table. - final Set ssaidUids = new HashSet<>( - getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id)); - ssaidUids.remove(SSAID_USER_KEY); + // Get all uids currently stored in the user's ssaid table. + final Set ssaidUids = new HashSet<>( + getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id)); + ssaidUids.remove(SSAID_USER_KEY); - // Perform a set difference for the appUids and ssaidUids. - ssaidUids.removeAll(appUids); + // Perform a set difference for the appUids and ssaidUids. + ssaidUids.removeAll(appUids); - // If there are ssaidUids left over they need to be removed from the table. - final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, - user.id); - for (String uid : ssaidUids) { - ssaidSettings.deleteSettingLocked(uid); + // If there are ssaidUids left over they need to be removed from the table. + final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, + user.id); + for (String uid : ssaidUids) { + ssaidSettings.deleteSettingLocked(uid); + } } } } @@ -2908,7 +2908,7 @@ public class SettingsProvider extends ContentProvider { boolean someSettingChanged = false; Setting setting = settingsState.getSettingLocked(name); if (!SettingsState.isSystemPackage(getContext(), - setting.getPackageName())) { + setting.getPackageName(), INVALID_UID, userId)) { if (prefix != null && !setting.getName().startsWith(prefix)) { continue; } @@ -2928,7 +2928,7 @@ public class SettingsProvider extends ContentProvider { boolean someSettingChanged = false; Setting setting = settingsState.getSettingLocked(name); if (!SettingsState.isSystemPackage(getContext(), - setting.getPackageName())) { + setting.getPackageName(), INVALID_UID, userId)) { if (prefix != null && !setting.getName().startsWith(prefix)) { continue; } @@ -3006,38 +3006,40 @@ public class SettingsProvider extends ContentProvider { return mSettingsStates.get(key); } - private void migrateAllLegacySettingsIfNeededLocked() { - final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); - File globalFile = getSettingsFile(key); - if (SettingsState.stateFileExists(globalFile)) { - return; - } - - mSettingsCreationBuildId = Build.ID; - - final long identity = Binder.clearCallingIdentity(); - try { - List users = mUserManager.getAliveUsers(); - - final int userCount = users.size(); - for (int i = 0; i < userCount; i++) { - final int userId = users.get(i).id; - - DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId); - SQLiteDatabase database = dbHelper.getWritableDatabase(); - migrateLegacySettingsForUserLocked(dbHelper, database, userId); - - // Upgrade to the latest version. - UpgradeController upgrader = new UpgradeController(userId); - upgrader.upgradeIfNeededLocked(); - - // Drop from memory if not a running user. - if (!mUserManager.isUserRunning(new UserHandle(userId))) { - removeUserStateLocked(userId, false); - } + private void migrateAllLegacySettingsIfNeeded() { + synchronized (mLock) { + final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM); + File globalFile = getSettingsFile(key); + if (SettingsState.stateFileExists(globalFile)) { + return; + } + + mSettingsCreationBuildId = Build.ID; + + final long identity = Binder.clearCallingIdentity(); + try { + List users = mUserManager.getAliveUsers(); + + final int userCount = users.size(); + for (int i = 0; i < userCount; i++) { + final int userId = users.get(i).id; + + DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId); + SQLiteDatabase database = dbHelper.getWritableDatabase(); + migrateLegacySettingsForUserLocked(dbHelper, database, userId); + + // Upgrade to the latest version. + UpgradeController upgrader = new UpgradeController(userId); + upgrader.upgradeIfNeededLocked(); + + // Drop from memory if not a running user. + if (!mUserManager.isUserRunning(new UserHandle(userId))) { + removeUserStateLocked(userId, false); + } + } + } finally { + Binder.restoreCallingIdentity(identity); } - } finally { - Binder.restoreCallingIdentity(identity); } } @@ -5031,9 +5033,19 @@ public class SettingsProvider extends ContentProvider { // In the upgrade case we pretend the call is made from the app // that made the last change to the setting to properly determine // whether the call has been made by a system component. + int callingUid = -1; try { - final boolean systemSet = SettingsState.isSystemPackage( - getContext(), setting.getPackageName()); + callingUid = mPackageManager.getPackageUid(setting.getPackageName(), 0, userId); + } catch (RemoteException e) { + /* ignore - handled below */ + } + if (callingUid < 0) { + Slog.e(LOG_TAG, "Unknown package: " + setting.getPackageName()); + continue; + } + try { + final boolean systemSet = SettingsState.isSystemPackage(getContext(), + setting.getPackageName(), callingUid, userId); if (systemSet) { settings.insertSettingOverrideableByRestoreLocked(name, setting.getValue(), setting.getTag(), true, setting.getPackageName()); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 911ff9916d6c6..53d868ac00501 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -17,13 +17,14 @@ package com.android.providers.settings; import static android.os.Process.FIRST_APPLICATION_UID; +import static android.os.Process.INVALID_UID; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.os.Binder; import android.os.Build; import android.os.FileUtils; @@ -36,10 +37,10 @@ import android.provider.Settings; import android.providers.settings.SettingsOperationProto; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.AtomicFile; import android.util.Base64; import android.util.Slog; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; @@ -148,7 +149,13 @@ final class SettingsState { private static final String NULL_VALUE = "null"; - private static final ArraySet sSystemPackages = new ArraySet<>(); + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static final SparseIntArray sSystemUids = new SparseIntArray(); + + @GuardedBy("sLock") + private static Signature sSystemSignature; private final Object mWriteLock = new Object(); @@ -634,7 +641,7 @@ final class SettingsState { /** * Dump historical operations as a proto buf. * - * @param proto The proto buf stream to dump to + * @param proto The proto buf stream to dump to * @param fieldId The repeated field ID to use to save an operation to. */ void dumpHistoricalOperations(@NonNull ProtoOutputStream proto, long fieldId) { @@ -1041,7 +1048,6 @@ final class SettingsState { /** * Uses AtomicFile to check if the file or its backup exists. - * * @param file The file to check for existence * @return whether the original or backup exist */ @@ -1301,9 +1307,9 @@ final class SettingsState { if (NULL_VALUE.equals(value)) { value = null; } + final boolean callerSystem = !forceNonSystemPackage && - !isNull() && (isCalledFromSystem(packageName) - || isSystemPackage(mContext, packageName)); + !isNull() && isSystemPackage(mContext, packageName); // Settings set by the system are always defaults. if (callerSystem) { setDefault = true; @@ -1428,92 +1434,98 @@ final class SettingsState { return sb.toString(); } - // Cache the list of names of system packages. This is only called once on system boot. - public static void cacheSystemPackageNamesAndSystemSignature(@NonNull Context context) { - final PackageManager packageManager = context.getPackageManager(); - final long identity = Binder.clearCallingIdentity(); - try { - sSystemPackages.add(SYSTEM_PACKAGE_NAME); - // Cache SetupWizard package name. - final String setupWizPackageName = packageManager.getSetupWizardPackageName(); - if (setupWizPackageName != null) { - sSystemPackages.add(setupWizPackageName); + // Check if a specific package belonging to the caller is part of the system package. + public static boolean isSystemPackage(Context context, String packageName) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + return isSystemPackage(context, packageName, callingUid, callingUserId); + } + + // Check if a specific package, uid, and user ID are part of the system package. + public static boolean isSystemPackage(Context context, String packageName, int uid, + int userId) { + synchronized (sLock) { + if (SYSTEM_PACKAGE_NAME.equals(packageName)) { + return true; } - final List packageInfos = packageManager.getInstalledPackages(0); - final int installedPackagesCount = packageInfos.size(); - for (int i = 0; i < installedPackagesCount; i++) { - if (shouldAddToSystemPackages(packageInfos.get(i))) { - sSystemPackages.add(packageInfos.get(i).packageName); + + // Shell and Root are not considered a part of the system + if (SHELL_PACKAGE_NAME.equals(packageName) + || ROOT_PACKAGE_NAME.equals(packageName)) { + return false; + } + + if (uid != INVALID_UID) { + // Native services running as a special UID get a pass + final int callingAppId = UserHandle.getAppId(uid); + if (callingAppId < FIRST_APPLICATION_UID) { + sSystemUids.put(callingAppId, callingAppId); + return true; } } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - private static boolean shouldAddToSystemPackages(@NonNull PackageInfo packageInfo) { - // Shell and Root are not considered a part of the system - if (isShellOrRoot(packageInfo.packageName)) { + final long identity = Binder.clearCallingIdentity(); + try { + try { + uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, userId); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + + // If the system or a special system UID (like telephony), done. + if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) { + sSystemUids.put(uid, uid); + return true; + } + + // If already known system component, done. + if (sSystemUids.indexOfKey(uid) >= 0) { + return true; + } + + // If SetupWizard, done. + String setupWizPackage = context.getPackageManager().getSetupWizardPackageName(); + if (packageName.equals(setupWizPackage)) { + sSystemUids.put(uid, uid); + return true; + } + + // If a persistent system app, done. + PackageInfo packageInfo; + try { + packageInfo = context.getPackageManager().getPackageInfoAsUser( + packageName, PackageManager.GET_SIGNATURES, userId); + if ((packageInfo.applicationInfo.flags + & ApplicationInfo.FLAG_PERSISTENT) != 0 + && (packageInfo.applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) != 0) { + sSystemUids.put(uid, uid); + return true; + } + } catch (PackageManager.NameNotFoundException e) { + return false; + } + + // Last check if system signed. + if (sSystemSignature == null) { + try { + sSystemSignature = context.getPackageManager().getPackageInfoAsUser( + SYSTEM_PACKAGE_NAME, PackageManager.GET_SIGNATURES, + UserHandle.USER_SYSTEM).signatures[0]; + } catch (PackageManager.NameNotFoundException e) { + /* impossible */ + return false; + } + } + if (sSystemSignature.equals(packageInfo.signatures[0])) { + sSystemUids.put(uid, uid); + return true; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + return false; } - // Already added - if (sSystemPackages.contains(packageInfo.packageName)) { - return false; - } - return isSystemPackage(packageInfo.applicationInfo); - } - - private static boolean isShellOrRoot(@NonNull String packageName) { - return (SHELL_PACKAGE_NAME.equals(packageName) - || ROOT_PACKAGE_NAME.equals(packageName)); - } - - private static boolean isCalledFromSystem(@NonNull String packageName) { - // Shell and Root are not considered a part of the system - if (isShellOrRoot(packageName)) { - return false; - } - final int callingUid = Binder.getCallingUid(); - // Native services running as a special UID get a pass - final int callingAppId = UserHandle.getAppId(callingUid); - return (callingAppId < FIRST_APPLICATION_UID); - } - - public static boolean isSystemPackage(@NonNull Context context, @NonNull String packageName) { - // Check shell or root before trying to retrieve ApplicationInfo to fail fast - if (isShellOrRoot(packageName)) { - return false; - } - // If it's a known system package or known to be platform signed - if (sSystemPackages.contains(packageName)) { - return true; - } - ApplicationInfo aInfo = null; - try { - // Notice that this makes a call to package manager inside the lock - aInfo = context.getPackageManager().getApplicationInfo(packageName, 0); - } catch (PackageManager.NameNotFoundException ignored) { - } - return isSystemPackage(aInfo); - } - - private static boolean isSystemPackage(@Nullable ApplicationInfo aInfo) { - if (aInfo == null) { - return false; - } - // If the system or a special system UID (like telephony), done. - if (aInfo.uid < FIRST_APPLICATION_UID) { - return true; - } - // If a persistent system app, done. - if ((aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 - && (aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - return true; - } - // Platform signed packages are considered to be from the system - if (aInfo.isSignedWithPlatformKey()) { - return true; - } - return false; } }