Merge "Include GIDs for unenforced permissions."
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index c000bdf..c402329 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1057,6 +1057,15 @@
             return true;
         }
 
+        case KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String reason = data.readString();
+            boolean res = killProcessesBelowForeground(reason);
+            reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
+            return true;
+        }
+
         case START_RUNNING_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
@@ -2910,6 +2919,18 @@
         reply.recycle();
         return res;
     }
+    @Override
+    public boolean killProcessesBelowForeground(String reason) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(reason);
+        mRemote.transact(KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION, data, reply, 0);
+        boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
     public void startRunning(String pkg, String cls, String action,
             String indata) throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a809cc1..1d994d8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -216,9 +216,10 @@
     public void enterSafeMode() throws RemoteException;
     
     public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
-    
+
     public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
-    
+    public boolean killProcessesBelowForeground(String reason) throws RemoteException;
+
     // Special low-level communication with activity manager.
     public void startRunning(String pkg, String cls, String action,
             String data) throws RemoteException;
@@ -573,4 +574,5 @@
     int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
     int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
     int GET_MY_MEMORY_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+142;
+    int KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+143;
 }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 84fcd5e..60749b3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6997,7 +6997,43 @@
         }
         return killed;
     }
-    
+
+    @Override
+    public boolean killProcessesBelowForeground(String reason) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("killProcessesBelowForeground() only available to system");
+        }
+
+        return killProcessesBelowAdj(ProcessList.FOREGROUND_APP_ADJ, reason);
+    }
+
+    private boolean killProcessesBelowAdj(int belowAdj, String reason) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("killProcessesBelowAdj() only available to system");
+        }
+
+        boolean killed = false;
+        synchronized (mPidsSelfLocked) {
+            final int size = mPidsSelfLocked.size();
+            for (int i = 0; i < size; i++) {
+                final int pid = mPidsSelfLocked.keyAt(i);
+                final ProcessRecord proc = mPidsSelfLocked.valueAt(i);
+                if (proc == null) continue;
+
+                final int adj = proc.setAdj;
+                if (adj > belowAdj && !proc.killedBackground) {
+                    Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
+                    EventLog.writeEvent(
+                            EventLogTags.AM_KILL, proc.pid, proc.processName, adj, reason);
+                    killed = true;
+                    proc.killedBackground = true;
+                    Process.killProcessQuiet(pid);
+                }
+            }
+        }
+        return killed;
+    }
+
     public final void startRunning(String pkg, String cls, String action,
             String data) {
         synchronized(this) {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 95666c0..067bf28 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1587,7 +1587,16 @@
             if (p != null) {
                 final PackageSetting ps = (PackageSetting)p.mExtras;
                 final SharedUserSetting suid = ps.sharedUser;
-                return suid != null ? suid.gids : ps.gids;
+                int[] gids = suid != null ? suid.gids : ps.gids;
+
+                // include GIDs for any unenforced permissions
+                if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE)) {
+                    final BasePermission basePerm = mSettings.mPermissions.get(
+                            READ_EXTERNAL_STORAGE);
+                    gids = appendInts(gids, basePerm.gids);
+                }
+
+                return gids;
             }
         }
         // stupid thing to indicate an error.
@@ -8890,6 +8899,19 @@
                 if (mSettings.mReadExternalStorageEnforcement != enforcement) {
                     mSettings.mReadExternalStorageEnforcement = enforcement;
                     mSettings.writeLPr();
+
+                    // kill any non-foreground processes so we restart them and
+                    // grant/revoke the GID.
+                    final IActivityManager am = ActivityManagerNative.getDefault();
+                    if (am != null) {
+                        final long token = Binder.clearCallingIdentity();
+                        try {
+                            am.killProcessesBelowForeground("setPermissionEnforcement");
+                        } catch (RemoteException e) {
+                        } finally {
+                            Binder.restoreCallingIdentity(token);
+                        }
+                    }
                 }
             }
         } else {