DO NOT MERGE revoke certain app-ops on suspend
Revoking an apps authorizations to use camera and record or play audio while suspended. Appops watchers will also be notified of this change to re-evaluate privileges at the time of suspension. Test: atest FrameworksServicesTests:SuspendPackagesTest Bug: 138636979 Change-Id: Ie95555856afdd56728125f7e60b6a78cf9fc0e58 Merged-In: Ie95555856afdd56728125f7e60b6a78cf9fc0e58 Merged-In: Ic5fb1807deceabfd956b666fa76f8bcc94020ac3
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user