Merge "Allow device/profile owners to change app ops modes." into pi-dev

This commit is contained in:
Dianne Hackborn
2018-05-14 20:43:31 +00:00
committed by Android (Google) Code Review
4 changed files with 143 additions and 18 deletions

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.util.SparseIntArray;
/**
* App ops service local interface.
*
* @hide Only for use within the system server.
*/
public abstract class AppOpsManagerInternal {
/**
* Set the currently configured device and profile owners. Specifies the package uid (value)
* that has been configured for each user (key) that has one. These will be allowed privileged
* access to app ops for their user.
*/
public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
}

View File

@@ -21,6 +21,7 @@ import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -172,6 +173,9 @@ public class AppOpsService extends IAppOpsService.Stub {
final AtomicFile mFile;
final Handler mHandler;
private final AppOpsManagerInternalImpl mAppOpsManagerInternal
= new AppOpsManagerInternalImpl();
boolean mWriteScheduled;
boolean mFastWriteScheduled;
final Runnable mWriteRunner = new Runnable() {
@@ -200,6 +204,8 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
SparseIntArray mProfileOwners;
/**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
@@ -551,6 +557,7 @@ public class AppOpsService extends IAppOpsService.Stub {
public void publish(Context context) {
mContext = context;
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
}
public void systemReady() {
@@ -921,12 +928,27 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
if (callingPid == Process.myPid()) {
return;
}
final int callingUser = UserHandle.getUserId(callingUid);
synchronized (this) {
if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
// Profile owners are allowed to change modes but only for apps
// within their user.
return;
}
}
}
mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
@Override
public void setUidMode(int code, int uid, int mode) {
if (Binder.getCallingPid() != Process.myPid()) {
mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
code = AppOpsManager.opToSwitch(code);
@@ -1029,10 +1051,7 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void setMode(int code, int uid, String packageName, int mode) {
if (Binder.getCallingPid() != Process.myPid()) {
mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -1151,8 +1170,6 @@ public class AppOpsService extends IAppOpsService.Stub {
public void resetAllModes(int reqUserId, String reqPackageName) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
callingPid, callingUid, null);
reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
true, true, "resetAllModes", null);
@@ -1166,6 +1183,8 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
enforceManageAppOpsModes(callingPid, callingUid, reqUid);
HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
synchronized (this) {
boolean changed = false;
@@ -1428,10 +1447,9 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void setAudioRestriction(int code, int usage, int uid, int mode,
String[] exceptionPackages) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingUid(uid);
verifyIncomingOp(code);
mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
synchronized (this) {
SparseArray<Restriction> usageRestrictions = mAudioRestrictions.get(code);
if (usageRestrictions == null) {
@@ -2809,9 +2827,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return 0;
}
case "write-settings": {
shell.mInternal.mContext.enforcePermission(
android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
Binder.getCallingUid(), -1);
long token = Binder.clearCallingIdentity();
try {
synchronized (shell.mInternal) {
@@ -2825,9 +2842,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return 0;
}
case "read-settings": {
shell.mInternal.mContext.enforcePermission(
android.Manifest.permission.MANAGE_APP_OPS_MODES,
Binder.getCallingPid(), Binder.getCallingUid(), null);
shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
Binder.getCallingUid(), -1);
long token = Binder.clearCallingIdentity();
try {
shell.mInternal.readState();
@@ -2989,6 +3005,17 @@ public class AppOpsService extends IAppOpsService.Stub {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final Date date = new Date();
boolean needSep = false;
if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null) {
pw.println(" Profile owners:");
for (int poi = 0; poi < mProfileOwners.size(); poi++) {
pw.print(" User #");
pw.print(mProfileOwners.keyAt(poi));
pw.print(": ");
UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
pw.println();
}
pw.println();
}
if (mOpModeWatchers.size() > 0) {
boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
@@ -3702,4 +3729,12 @@ public class AppOpsService extends IAppOpsService.Stub {
return true;
}
}
private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
@Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
synchronized (AppOpsService.this) {
mProfileOwners = owners;
}
}
}
}

View File

@@ -3351,6 +3351,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
case SystemService.PHASE_LOCK_SETTINGS_READY:
onLockSettingsReady();
loadAdminDataAsync();
mOwners.systemReady();
break;
case SystemService.PHASE_BOOT_COMPLETED:
ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.

View File

@@ -17,11 +17,14 @@
package com.android.server.devicepolicy;
import android.annotation.Nullable;
import android.app.AppOpsManagerInternal;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
@@ -32,10 +35,12 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,6 +104,8 @@ class Owners {
private final UserManagerInternal mUserManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
private boolean mSystemReady;
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
@@ -179,6 +186,7 @@ class Owners {
getDeviceOwnerUserId()));
}
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -262,6 +270,7 @@ class Owners {
mUserManagerInternal.setDeviceManaged(true);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -272,6 +281,7 @@ class Owners {
mUserManagerInternal.setDeviceManaged(false);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -283,6 +293,7 @@ class Owners {
/* remoteBugreportHash =*/ null));
mUserManagerInternal.setUserManaged(userId, true);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -291,6 +302,7 @@ class Owners {
mProfileOwners.remove(userId);
mUserManagerInternal.setUserManaged(userId, false);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -302,6 +314,7 @@ class Owners {
ownerInfo.remoteBugreportHash);
mProfileOwners.put(userId, newOwnerInfo);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -313,6 +326,7 @@ class Owners {
mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
mDeviceOwner.remoteBugreportHash);
pushToPackageManagerLocked();
pushToAppOpsLocked();
}
}
@@ -581,6 +595,48 @@ class Owners {
}
}
void pushToAppOpsLocked() {
if (!mSystemReady) {
return;
}
final long ident = Binder.clearCallingIdentity();
try {
final SparseIntArray owners = new SparseIntArray();
if (mDeviceOwner != null) {
final int uid = mPackageManagerInternal.getPackageUid(mDeviceOwner.packageName,
PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
mDeviceOwnerUserId);
if (uid >= 0) {
owners.put(mDeviceOwnerUserId, uid);
}
}
if (mProfileOwners != null) {
for (int poi = mProfileOwners.size() - 1; poi >= 0; poi--) {
final int uid = mPackageManagerInternal.getPackageUid(
mProfileOwners.valueAt(poi).packageName,
PackageManager.MATCH_ALL | PackageManager.MATCH_KNOWN_PACKAGES,
mProfileOwners.keyAt(poi));
if (uid >= 0) {
owners.put(mProfileOwners.keyAt(poi), uid);
}
}
}
AppOpsManagerInternal appops = LocalServices.getService(AppOpsManagerInternal.class);
if (appops != null) {
appops.setDeviceAndProfileOwners(owners.size() > 0 ? owners : null);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
public void systemReady() {
synchronized (mLock) {
mSystemReady = true;
pushToAppOpsLocked();
}
}
private abstract static class FileReadWriter {
private final File mFile;