System settings can be changed by system apps.

The system settings permission is going away and the user will
be able to choose which apps have access to system settings in
the UI. So, if an app is white-listed by the user or being on
the system image, we allow access to system settings. Also if
the caller has the stronger write secure settings permission
we allow changes of the less sensitive system settings.

Change-Id: I7aca958fd0ad2c588117b8c6e44d78eb16d648bc
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aff6ad8..44b9d8b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -904,16 +904,16 @@
 
     private boolean mutateSystemSetting(String name, String value, int runAsUserId,
             int operation) {
-        // Make sure the caller can change the settings.
-        enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
+        // Check for permissions first.
+        hasPermissionsToMutateSystemSettings();
 
         // Verify whether this operation is allowed for the calling package.
         if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
             return false;
         }
 
-        // Enforce what the calling package can mutate in the system settings.
-        enforceRestrictedSystemSettingsMutationForCallingPackageLocked(operation, name);
+        // Enforce what the calling package can mutate the system settings.
+        enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name);
 
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
@@ -954,6 +954,28 @@
         }
     }
 
+    private boolean hasPermissionsToMutateSystemSettings() {
+        // Write secure settings is a more protected permission. If caller has it we are good.
+        if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+
+        // The write settings permission gates mutation of system settings.
+        if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SETTINGS)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+
+        // Excpet we let system apps change system settings without the permission.
+        PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+        if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            return true;
+        }
+
+        return false;
+    }
+
     private void validateSystemSettingValue(String name, String value) {
         Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
         if (validator != null && !validator.validate(value)) {
@@ -1000,7 +1022,7 @@
         return userId;
     }
 
-    private void enforceRestrictedSystemSettingsMutationForCallingPackageLocked(int operation,
+    private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
             String name) {
         // System/root/shell can mutate whatever secure settings they want.
         final int callingUid = Binder.getCallingUid();