Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b8336f2 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by android-build-merger
Browse files

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

am: 82a87674

Change-Id: Id4a52aaca3d94075ff179141e96fba5c7326d4ee
parents f907c6f7 82a87674
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+53 −18
Original line number Diff line number Diff line
@@ -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 {
        }
    }

    @Override
    public void setUidMode(int code, int uid, int mode) {
        if (Binder.getCallingPid() != Process.myPid()) {
    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) {
        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;
            }
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -3352,6 +3352,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.
+56 −0
Original line number Diff line number Diff line
@@ -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;