summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/AppOpsService.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java50
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();