diff options
| -rw-r--r-- | services/core/java/com/android/server/AppOpsService.java | 50 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java | 50 |
2 files changed, 100 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 786d757557d1..0950042e453b 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -22,8 +22,11 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; @@ -96,6 +99,9 @@ import java.util.List; import java.util.Map; import static android.app.AppOpsManager._NUM_UID_STATE; +import static android.app.AppOpsManager.OP_CAMERA; +import static android.app.AppOpsManager.OP_PLAY_AUDIO; +import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.UID_STATE_BACKGROUND; import static android.app.AppOpsManager.UID_STATE_CACHED; import static android.app.AppOpsManager.UID_STATE_FOREGROUND; @@ -170,6 +176,12 @@ public class AppOpsService extends IAppOpsService.Stub { "rc", // UID_STATE_CACHED }; + private static final int[] OPS_RESTRICTED_ON_SUSPEND = { + OP_PLAY_AUDIO, + OP_RECORD_AUDIO, + OP_CAMERA, + }; + Context mContext; final AtomicFile mFile; final Handler mHandler; @@ -635,6 +647,33 @@ public class AppOpsService extends IAppOpsService.Stub { } } + final IntentFilter packageSuspendFilter = new IntentFilter(); + packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); + packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String[] changedPkgs = intent.getStringArrayExtra( + Intent.EXTRA_CHANGED_PACKAGE_LIST); + for (int code : OPS_RESTRICTED_ON_SUSPEND) { + ArraySet<ModeCallback> callbacks; + synchronized (AppOpsService.this) { + callbacks = mOpModeWatchers.get(code); + if (callbacks == null) { + continue; + } + callbacks = new ArraySet<>(callbacks); + } + for (int i = 0; i < changedPkgs.length; i++) { + final String changedPkg = changedPkgs[i]; + // We trust packagemanager to insert matching uid and packageNames in the + // extras + notifyOpChanged(callbacks, code, -1, changedPkg); + } + } + } + }, packageSuspendFilter); + PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); packageManagerInternal.setExternalSourcesPolicy( @@ -1419,6 +1458,9 @@ public class AppOpsService extends IAppOpsService.Stub { if (resolvedPackageName == null) { return AppOpsManager.MODE_IGNORED; } + if (isOpRestrictedDueToSuspend(code, packageName, uid)) { + return AppOpsManager.MODE_IGNORED; + } synchronized (this) { if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { return AppOpsManager.MODE_IGNORED; @@ -1461,6 +1503,14 @@ public class AppOpsService extends IAppOpsService.Stub { return checkOperation(code, uid, packageName); } + private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) { + if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) { + return false; + } + final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); + } + private boolean isPackageSuspendedForUser(String pkg, int uid) { try { return AppGlobals.getPackageManager().isPackageSuspendedForUser( diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java index c186e48e8794..8460d77215e4 100644 --- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java @@ -16,6 +16,13 @@ package com.android.server.pm; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_IGNORED; +import static android.app.AppOpsManager.OP_CAMERA; +import static android.app.AppOpsManager.OP_PLAY_AUDIO; +import static android.app.AppOpsManager.OP_RECORD_AUDIO; +import static android.app.AppOpsManager.opToName; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -40,6 +47,7 @@ import android.os.Handler; import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.support.test.InstrumentationRegistry; import android.support.test.filters.LargeTest; @@ -52,6 +60,8 @@ import android.util.Log; import android.view.IWindowManager; import android.view.WindowManagerGlobal; +import com.android.internal.app.IAppOpsCallback; +import com.android.internal.app.IAppOpsService; import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity; import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver; @@ -546,6 +556,46 @@ public class SuspendPackagesTest { assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction()); } + @Test + public void testCameraBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_CAMERA); + } + + @Test + public void testPlayAudioBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_PLAY_AUDIO); + } + + @Test + public void testRecordAudioBlockedOnSuspend() throws Exception { + assertOpBlockedOnSuspend(OP_RECORD_AUDIO); + } + + private void assertOpBlockedOnSuspend(int code) throws Exception { + final IAppOpsService iAppOps = IAppOpsService.Stub.asInterface( + ServiceManager.getService(Context.APP_OPS_SERVICE)); + final CountDownLatch latch = new CountDownLatch(1); + final IAppOpsCallback watcher = new IAppOpsCallback.Stub() { + @Override + public void opChanged(int op, int uid, String packageName) { + if (op == code && packageName.equals(TEST_APP_PACKAGE_NAME)) { + latch.countDown(); + } + } + }; + iAppOps.startWatchingMode(code, TEST_APP_PACKAGE_NAME, watcher); + final int testPackageUid = mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0); + int opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + assertEquals("Op " + opToName(code) + " disallowed for unsuspended package", MODE_ALLOWED, + opMode); + suspendTestPackage(null, null, null); + assertTrue("AppOpsWatcher did not callback", latch.await(5, TimeUnit.SECONDS)); + opMode = iAppOps.checkOperation(code, testPackageUid, TEST_APP_PACKAGE_NAME); + assertEquals("Op " + opToName(code) + " allowed for suspended package", MODE_IGNORED, + opMode); + iAppOps.stopWatchingMode(watcher); + } + @After public void tearDown() throws IOException { mAppCommsReceiver.unregister(); |