Loading core/java/android/provider/Settings.java +56 −17 Original line number Diff line number Diff line Loading @@ -2773,6 +2773,7 @@ public final class Settings { private final ArraySet<String> mReadableFields; private final ArraySet<String> mAllFields; private final ArrayMap<String, Integer> mReadableFieldsWithMaxTargetSdk; @GuardedBy("this") private GenerationTracker mGenerationTracker; Loading @@ -2794,7 +2795,9 @@ public final class Settings { mProviderHolder = providerHolder; mReadableFields = new ArraySet<>(); mAllFields = new ArraySet<>(); getPublicSettingsForClass(callerClass, mAllFields, mReadableFields); mReadableFieldsWithMaxTargetSdk = new ArrayMap<>(); getPublicSettingsForClass(callerClass, mAllFields, mReadableFields, mReadableFieldsWithMaxTargetSdk); } public boolean putStringForUser(ContentResolver cr, String name, String value, Loading Loading @@ -2851,13 +2854,34 @@ public final class Settings { // Settings.Global and is not annotated as @Readable. // Notice that a key string that is not defined in any of the Settings.* classes will // still be regarded as readable. if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name) && !mReadableFields.contains(name)) { if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name)) { if (!mReadableFields.contains(name)) { throw new SecurityException( "Settings key: <" + name + "> is not readable. From S+, settings keys " + "annotated with @hide are restricted to system_server and system " + "apps only, unless they are annotated with @Readable."); + "annotated with @hide are restricted to system_server and " + "system apps only, unless they are annotated with @Readable." ); } else { // When the target settings key has @Readable annotation, if the caller app's // target sdk is higher than the maxTargetSdk of the annotation, reject access. if (mReadableFieldsWithMaxTargetSdk.containsKey(name)) { final int maxTargetSdk = mReadableFieldsWithMaxTargetSdk.get(name); final Application application = ActivityThread.currentApplication(); final boolean targetSdkCheckOk = application != null && application.getApplicationInfo() != null && application.getApplicationInfo().targetSdkVersion <= maxTargetSdk; if (!targetSdkCheckOk) { throw new SecurityException( "Settings key: <" + name + "> is only readable to apps with " + "targetSdkVersion lower than or equal to: " + maxTargetSdk ); } } } } final boolean isSelf = (userHandle == UserHandle.myUserId()); int currentGeneration = -1; if (isSelf) { Loading Loading @@ -3225,10 +3249,12 @@ public final class Settings { @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) private @interface Readable { int maxTargetSdk() default 0; } private static <T extends NameValueTable> void getPublicSettingsForClass( Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys) { Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> keysWithMaxTargetSdk) { final Field[] allFields = callerClass.getDeclaredFields(); try { for (int i = 0; i < allFields.length; i++) { Loading @@ -3241,8 +3267,15 @@ public final class Settings { continue; } allKeys.add((String) value); if (field.getAnnotation(Readable.class) != null) { readableKeys.add((String) value); final Readable annotation = field.getAnnotation(Readable.class); if (annotation != null) { final String key = (String) value; final int maxTargetSdk = annotation.maxTargetSdk(); readableKeys.add(key); if (maxTargetSdk != 0) { keysWithMaxTargetSdk.put(key, maxTargetSdk); } } } } catch (IllegalAccessException ignored) { Loading Loading @@ -3404,8 +3437,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(System.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(System.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /** Loading Loading @@ -5734,8 +5769,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(Secure.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(Secure.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /** Loading Loading @@ -11023,7 +11060,7 @@ public final class Settings { * @hide */ @UnsupportedAppUsage @Readable @Readable(maxTargetSdk = Build.VERSION_CODES.R) public static final String MOBILE_DATA = "mobile_data"; /** Loading Loading @@ -14965,8 +15002,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(Global.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(Global.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /** packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +40 −11 Original line number Diff line number Diff line Loading @@ -310,20 +310,29 @@ public class SettingsProvider extends ContentProvider { private static final Set<String> sAllSecureSettings = new ArraySet<>(); private static final Set<String> sReadableSecureSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableSecureSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings); Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings, sReadableSecureSettingsWithMaxTargetSdk); } private static final Set<String> sAllSystemSettings = new ArraySet<>(); private static final Set<String> sReadableSystemSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableSystemSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings); Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings, sReadableSystemSettingsWithMaxTargetSdk); } private static final Set<String> sAllGlobalSettings = new ArraySet<>(); private static final Set<String> sReadableGlobalSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableGlobalSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings); Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings, sReadableGlobalSettingsWithMaxTargetSdk); } private final Object mLock = new Object(); Loading Loading @@ -2065,7 +2074,7 @@ public class SettingsProvider extends ContentProvider { } if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { // Skip checking readable annotations for test_only apps checkReadableAnnotation(settingsType, settingName); checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion); } /** * some settings need additional permission check, this is to have a matching security Loading Loading @@ -2101,35 +2110,55 @@ public class SettingsProvider extends ContentProvider { /** * Check if the target settings key is readable. Reject if the caller app is trying to access a * settings key defined in the Settings.Secure, Settings.System or Settings.Global and is not * annotated as @Readable. * annotated as @Readable. Reject if the caller app is targeting an SDK level that is higher * than the maxTargetSdk specified in the @Readable annotation. * Notice that a key string that is not defined in any of the Settings.* classes will still be * regarded as readable. */ private void checkReadableAnnotation(int settingsType, String settingName) { private void checkReadableAnnotation(int settingsType, String settingName, int targetSdkVersion) { final Set<String> allFields; final Set<String> readableFields; final ArrayMap<String, Integer> readableFieldsWithMaxTargetSdk; switch (settingsType) { case SETTINGS_TYPE_GLOBAL: allFields = sAllGlobalSettings; readableFields = sReadableGlobalSettings; readableFieldsWithMaxTargetSdk = sReadableGlobalSettingsWithMaxTargetSdk; break; case SETTINGS_TYPE_SYSTEM: allFields = sAllSystemSettings; readableFields = sReadableSystemSettings; readableFieldsWithMaxTargetSdk = sReadableSystemSettingsWithMaxTargetSdk; break; case SETTINGS_TYPE_SECURE: allFields = sAllSecureSettings; readableFields = sReadableSecureSettings; readableFieldsWithMaxTargetSdk = sReadableSecureSettingsWithMaxTargetSdk; break; default: throw new IllegalArgumentException("Invalid settings type: " + settingsType); } if (allFields.contains(settingName) && !readableFields.contains(settingName)) { if (allFields.contains(settingName)) { if (!readableFields.contains(settingName)) { throw new SecurityException( "Settings key: <" + settingName + "> is not readable. From S+, settings keys " + "annotated with @hide are restricted to system_server and system " + "apps only, unless they are annotated with @Readable."); "Settings key: <" + settingName + "> is not readable. From S+, settings " + "keys annotated with @hide are restricted to system_server and " + "system apps only, unless they are annotated with @Readable." ); } else { if (readableFieldsWithMaxTargetSdk.containsKey(settingName)) { final int maxTargetSdk = readableFieldsWithMaxTargetSdk.get(settingName); if (targetSdkVersion > maxTargetSdk) { throw new SecurityException( "Settings key: <" + settingName + "> is only readable to apps with " + "targetSdkVersion lower than or equal to: " + maxTargetSdk ); } } } } } Loading Loading
core/java/android/provider/Settings.java +56 −17 Original line number Diff line number Diff line Loading @@ -2773,6 +2773,7 @@ public final class Settings { private final ArraySet<String> mReadableFields; private final ArraySet<String> mAllFields; private final ArrayMap<String, Integer> mReadableFieldsWithMaxTargetSdk; @GuardedBy("this") private GenerationTracker mGenerationTracker; Loading @@ -2794,7 +2795,9 @@ public final class Settings { mProviderHolder = providerHolder; mReadableFields = new ArraySet<>(); mAllFields = new ArraySet<>(); getPublicSettingsForClass(callerClass, mAllFields, mReadableFields); mReadableFieldsWithMaxTargetSdk = new ArrayMap<>(); getPublicSettingsForClass(callerClass, mAllFields, mReadableFields, mReadableFieldsWithMaxTargetSdk); } public boolean putStringForUser(ContentResolver cr, String name, String value, Loading Loading @@ -2851,13 +2854,34 @@ public final class Settings { // Settings.Global and is not annotated as @Readable. // Notice that a key string that is not defined in any of the Settings.* classes will // still be regarded as readable. if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name) && !mReadableFields.contains(name)) { if (!isCallerExemptFromReadableRestriction() && mAllFields.contains(name)) { if (!mReadableFields.contains(name)) { throw new SecurityException( "Settings key: <" + name + "> is not readable. From S+, settings keys " + "annotated with @hide are restricted to system_server and system " + "apps only, unless they are annotated with @Readable."); + "annotated with @hide are restricted to system_server and " + "system apps only, unless they are annotated with @Readable." ); } else { // When the target settings key has @Readable annotation, if the caller app's // target sdk is higher than the maxTargetSdk of the annotation, reject access. if (mReadableFieldsWithMaxTargetSdk.containsKey(name)) { final int maxTargetSdk = mReadableFieldsWithMaxTargetSdk.get(name); final Application application = ActivityThread.currentApplication(); final boolean targetSdkCheckOk = application != null && application.getApplicationInfo() != null && application.getApplicationInfo().targetSdkVersion <= maxTargetSdk; if (!targetSdkCheckOk) { throw new SecurityException( "Settings key: <" + name + "> is only readable to apps with " + "targetSdkVersion lower than or equal to: " + maxTargetSdk ); } } } } final boolean isSelf = (userHandle == UserHandle.myUserId()); int currentGeneration = -1; if (isSelf) { Loading Loading @@ -3225,10 +3249,12 @@ public final class Settings { @Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) private @interface Readable { int maxTargetSdk() default 0; } private static <T extends NameValueTable> void getPublicSettingsForClass( Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys) { Class<T> callerClass, Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> keysWithMaxTargetSdk) { final Field[] allFields = callerClass.getDeclaredFields(); try { for (int i = 0; i < allFields.length; i++) { Loading @@ -3241,8 +3267,15 @@ public final class Settings { continue; } allKeys.add((String) value); if (field.getAnnotation(Readable.class) != null) { readableKeys.add((String) value); final Readable annotation = field.getAnnotation(Readable.class); if (annotation != null) { final String key = (String) value; final int maxTargetSdk = annotation.maxTargetSdk(); readableKeys.add(key); if (maxTargetSdk != 0) { keysWithMaxTargetSdk.put(key, maxTargetSdk); } } } } catch (IllegalAccessException ignored) { Loading Loading @@ -3404,8 +3437,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(System.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(System.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /** Loading Loading @@ -5734,8 +5769,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(Secure.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(Secure.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /** Loading Loading @@ -11023,7 +11060,7 @@ public final class Settings { * @hide */ @UnsupportedAppUsage @Readable @Readable(maxTargetSdk = Build.VERSION_CODES.R) public static final String MOBILE_DATA = "mobile_data"; /** Loading Loading @@ -14965,8 +15002,10 @@ public final class Settings { } /** @hide */ public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys) { getPublicSettingsForClass(Global.class, allKeys, readableKeys); public static void getPublicSettings(Set<String> allKeys, Set<String> readableKeys, ArrayMap<String, Integer> readableKeysWithMaxTargetSdk) { getPublicSettingsForClass(Global.class, allKeys, readableKeys, readableKeysWithMaxTargetSdk); } /**
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +40 −11 Original line number Diff line number Diff line Loading @@ -310,20 +310,29 @@ public class SettingsProvider extends ContentProvider { private static final Set<String> sAllSecureSettings = new ArraySet<>(); private static final Set<String> sReadableSecureSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableSecureSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings); Settings.Secure.getPublicSettings(sAllSecureSettings, sReadableSecureSettings, sReadableSecureSettingsWithMaxTargetSdk); } private static final Set<String> sAllSystemSettings = new ArraySet<>(); private static final Set<String> sReadableSystemSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableSystemSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings); Settings.System.getPublicSettings(sAllSystemSettings, sReadableSystemSettings, sReadableSystemSettingsWithMaxTargetSdk); } private static final Set<String> sAllGlobalSettings = new ArraySet<>(); private static final Set<String> sReadableGlobalSettings = new ArraySet<>(); private static final ArrayMap<String, Integer> sReadableGlobalSettingsWithMaxTargetSdk = new ArrayMap<>(); static { Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings); Settings.Global.getPublicSettings(sAllGlobalSettings, sReadableGlobalSettings, sReadableGlobalSettingsWithMaxTargetSdk); } private final Object mLock = new Object(); Loading Loading @@ -2065,7 +2074,7 @@ public class SettingsProvider extends ContentProvider { } if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { // Skip checking readable annotations for test_only apps checkReadableAnnotation(settingsType, settingName); checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion); } /** * some settings need additional permission check, this is to have a matching security Loading Loading @@ -2101,35 +2110,55 @@ public class SettingsProvider extends ContentProvider { /** * Check if the target settings key is readable. Reject if the caller app is trying to access a * settings key defined in the Settings.Secure, Settings.System or Settings.Global and is not * annotated as @Readable. * annotated as @Readable. Reject if the caller app is targeting an SDK level that is higher * than the maxTargetSdk specified in the @Readable annotation. * Notice that a key string that is not defined in any of the Settings.* classes will still be * regarded as readable. */ private void checkReadableAnnotation(int settingsType, String settingName) { private void checkReadableAnnotation(int settingsType, String settingName, int targetSdkVersion) { final Set<String> allFields; final Set<String> readableFields; final ArrayMap<String, Integer> readableFieldsWithMaxTargetSdk; switch (settingsType) { case SETTINGS_TYPE_GLOBAL: allFields = sAllGlobalSettings; readableFields = sReadableGlobalSettings; readableFieldsWithMaxTargetSdk = sReadableGlobalSettingsWithMaxTargetSdk; break; case SETTINGS_TYPE_SYSTEM: allFields = sAllSystemSettings; readableFields = sReadableSystemSettings; readableFieldsWithMaxTargetSdk = sReadableSystemSettingsWithMaxTargetSdk; break; case SETTINGS_TYPE_SECURE: allFields = sAllSecureSettings; readableFields = sReadableSecureSettings; readableFieldsWithMaxTargetSdk = sReadableSecureSettingsWithMaxTargetSdk; break; default: throw new IllegalArgumentException("Invalid settings type: " + settingsType); } if (allFields.contains(settingName) && !readableFields.contains(settingName)) { if (allFields.contains(settingName)) { if (!readableFields.contains(settingName)) { throw new SecurityException( "Settings key: <" + settingName + "> is not readable. From S+, settings keys " + "annotated with @hide are restricted to system_server and system " + "apps only, unless they are annotated with @Readable."); "Settings key: <" + settingName + "> is not readable. From S+, settings " + "keys annotated with @hide are restricted to system_server and " + "system apps only, unless they are annotated with @Readable." ); } else { if (readableFieldsWithMaxTargetSdk.containsKey(settingName)) { final int maxTargetSdk = readableFieldsWithMaxTargetSdk.get(settingName); if (targetSdkVersion > maxTargetSdk) { throw new SecurityException( "Settings key: <" + settingName + "> is only readable to apps with " + "targetSdkVersion lower than or equal to: " + maxTargetSdk ); } } } } } Loading