DPM.isDeviceOwnerApp() and getDeviceOwner() now check calling user
- Previously on MNC, they would return the same result regardless who the calling user is. - Now they properly take DO user-id into account. Meaning, they'll always return false and null respectively, if the calling user doesn't run device owner. - Note isDeviceOwnerApp() is a public API and getDeviceOwner() is a system API. Meaning we're changing the behavior or non-private APIs. - Also cleaned up hidden APIs, and gave them explicit suffixes to avoid confusion. Bundled code should prefer them for clarity. Now we have: * APIs that work cross-users: They all require MANAGE_USERS. boolean isDeviceOwnerAppOnAnyUser(String packageName) ComponentName getDeviceOwnerComponentOnAnyUser() int getDeviceOwnerUserId() boolean isDeviceOwnedByDeviceOwner() String getDeviceOwnerNameOnAnyUser() * APIs that work within user. No permissions are required. boolean isDeviceOwnerAppOnCallingUser(String packageName) ComponentName getDeviceOwnerComponentOnCallingUser() Bug 24676413 Change-Id: I751a907c7aaf7b019335d67065d183236effaa80
This commit is contained in:
@ -89,6 +89,10 @@ public class DevicePolicyManager {
|
||||
private final Context mContext;
|
||||
private final IDevicePolicyManager mService;
|
||||
|
||||
// TODO Use it everywhere.
|
||||
private static final String REMOTE_EXCEPTION_MESSAGE =
|
||||
"Failed to talk with device policy manager service";
|
||||
|
||||
private DevicePolicyManager(Context context) {
|
||||
this(context, IDevicePolicyManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
|
||||
@ -686,7 +690,7 @@ public class DevicePolicyManager {
|
||||
* extra field. This will invoke a UI to bring the user through adding the profile owner admin
|
||||
* to remotely control restrictions on the user.
|
||||
*
|
||||
* <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
|
||||
* <p>The intent must be invoked via {@link Activity#startActivityForResult} to receive the
|
||||
* result of whether or not the user approved the action. If approved, the result will
|
||||
* be {@link Activity#RESULT_OK} and the component will be set as an active admin as well
|
||||
* as a profile owner.
|
||||
@ -2765,37 +2769,94 @@ public class DevicePolicyManager {
|
||||
* the setup process.
|
||||
* @param packageName the package name of the app, to compare with the registered device owner
|
||||
* app, if any.
|
||||
* @return whether or not the package is registered as the device owner app. Note this method
|
||||
* does *not* check weather the device owner is actually running on the current user.
|
||||
* @return whether or not the package is registered as the device owner app.
|
||||
*/
|
||||
public boolean isDeviceOwnerApp(String packageName) {
|
||||
return isDeviceOwnerAppOnCallingUser(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a package is registered as device owner, only when it's running on the
|
||||
* calling user.
|
||||
*
|
||||
* <p>Same as {@link #isDeviceOwnerApp}, but bundled code should use it for clarity.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isDeviceOwnerAppOnCallingUser(String packageName) {
|
||||
return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if a package is registered as device owner, even if it's running on a different
|
||||
* user.
|
||||
*
|
||||
* <p>Requires the MANAGE_USERS permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isDeviceOwnerAppOnAnyUser(String packageName) {
|
||||
return isDeviceOwnerAppOnAnyUserInner(packageName, /* callingUserOnly =*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return device owner component name, only when it's running on the calling user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public ComponentName getDeviceOwnerComponentOnCallingUser() {
|
||||
return getDeviceOwnerComponentInner(/* callingUserOnly =*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return device owner component name, even if it's running on a different user.
|
||||
*
|
||||
* <p>Requires the MANAGE_USERS permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public ComponentName getDeviceOwnerComponentOnAnyUser() {
|
||||
return getDeviceOwnerComponentInner(/* callingUserOnly =*/ false);
|
||||
}
|
||||
|
||||
private boolean isDeviceOwnerAppOnAnyUserInner(String packageName, boolean callingUserOnly) {
|
||||
if (packageName == null) {
|
||||
return false;
|
||||
}
|
||||
final ComponentName deviceOwner = getDeviceOwnerComponent();
|
||||
final ComponentName deviceOwner = getDeviceOwnerComponentInner(callingUserOnly);
|
||||
if (deviceOwner == null) {
|
||||
return false;
|
||||
}
|
||||
return packageName.equals(deviceOwner.getPackageName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Redirect to isDeviceOwnerApp.
|
||||
*/
|
||||
public boolean isDeviceOwner(String packageName) {
|
||||
return isDeviceOwnerApp(packageName);
|
||||
private ComponentName getDeviceOwnerComponentInner(boolean callingUserOnly) {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getDeviceOwnerComponent(callingUserOnly);
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given component is registered as a device owner.
|
||||
* Note this method does *not* check weather the device owner is actually running on the current
|
||||
* user.
|
||||
* @return ID of the user who runs device owner, or {@link UserHandle#USER_NULL} if there's
|
||||
* no device owner.
|
||||
*
|
||||
* <p>Requires the MANAGE_USERS permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isDeviceOwner(ComponentName who) {
|
||||
return (who != null) && who.equals(getDeviceOwner());
|
||||
public int getDeviceOwnerUserId() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getDeviceOwnerUserId();
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
return UserHandle.USER_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2818,46 +2879,43 @@ public class DevicePolicyManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device owner package name. Note this method will still return the device owner
|
||||
* package name even if it's running on a different user.
|
||||
* Returns the device owner package name, only if it's running on the calling user.
|
||||
*
|
||||
* <p>Bundled components should use {@code getDeviceOwnerComponentOnCallingUser()} for clarity.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public String getDeviceOwner() {
|
||||
final ComponentName componentName = getDeviceOwnerComponent();
|
||||
return componentName == null ? null : componentName.getPackageName();
|
||||
final ComponentName name = getDeviceOwnerComponentOnCallingUser();
|
||||
return name != null ? name.getPackageName() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device owner name. Note this method will still return the device owner
|
||||
* name even if it's running on a different user.
|
||||
* @return true if the device is managed by any device owner.
|
||||
*
|
||||
* <p>Requires the MANAGE_USERS permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String getDeviceOwnerName() {
|
||||
public boolean isDeviceManaged() {
|
||||
return getDeviceOwnerComponentOnAnyUser() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device owner name. Note this method *will* return the device owner
|
||||
* name when it's running on a different user.
|
||||
*
|
||||
* <p>Requires the MANAGE_USERS permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String getDeviceOwnerNameOnAnyUser() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getDeviceOwnerName();
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Failed to get device owner");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device owner component name. Note this method will still return the device owner
|
||||
* component name even if it's running on a different user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public ComponentName getDeviceOwnerComponent() {
|
||||
if (mService != null) {
|
||||
try {
|
||||
return mService.getDeviceOwner();
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Failed to get device owner");
|
||||
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -3130,7 +3188,7 @@ public class DevicePolicyManager {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* @param user The user for whom to fetch the profile owner name, if any.
|
||||
* @param userId The user for whom to fetch the profile owner name, if any.
|
||||
* @return the human readable name of the organisation associated with this profile owner or
|
||||
* null if one is not set.
|
||||
* @throws IllegalArgumentException if the userId is invalid.
|
||||
|
@ -114,9 +114,10 @@ interface IDevicePolicyManager {
|
||||
void reportSuccessfulPasswordAttempt(int userHandle);
|
||||
|
||||
boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
|
||||
ComponentName getDeviceOwner();
|
||||
ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
|
||||
String getDeviceOwnerName();
|
||||
void clearDeviceOwner(String packageName);
|
||||
int getDeviceOwnerUserId();
|
||||
|
||||
boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
|
||||
ComponentName getProfileOwner(int userHandle);
|
||||
|
@ -111,7 +111,9 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
|
||||
|
||||
private void handleRefreshState() {
|
||||
mIsIconVisible = mSecurityController.isVpnEnabled();
|
||||
if (mSecurityController.hasDeviceOwner()) {
|
||||
// If the device has device owner, show "Device may be monitored", but --
|
||||
// TODO See b/25779452 -- device owner doesn't actually have monitoring power.
|
||||
if (mSecurityController.isDeviceManaged()) {
|
||||
mFooterTextId = R.string.device_owned_footer;
|
||||
mIsVisible = true;
|
||||
} else {
|
||||
@ -156,6 +158,8 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
|
||||
|
||||
private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
|
||||
String profileVpn, boolean primaryUserIsManaged) {
|
||||
// Show a special warning when the device has device owner, but --
|
||||
// TODO See b/25779452 -- device owner doesn't actually have monitoring power.
|
||||
if (deviceOwner != null) {
|
||||
if (primaryVpn != null) {
|
||||
return mContext.getString(R.string.monitoring_description_vpn_app_device_owned,
|
||||
|
@ -16,8 +16,8 @@
|
||||
package com.android.systemui.statusbar.policy;
|
||||
|
||||
public interface SecurityController {
|
||||
|
||||
boolean hasDeviceOwner();
|
||||
/** Whether the device has device owner, even if not on this user. */
|
||||
boolean isDeviceManaged();
|
||||
boolean hasProfileOwner();
|
||||
String getDeviceOwnerName();
|
||||
String getProfileOwnerName();
|
||||
|
@ -102,13 +102,13 @@ public class SecurityControllerImpl implements SecurityController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDeviceOwner() {
|
||||
return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner());
|
||||
public boolean isDeviceManaged() {
|
||||
return mDevicePolicyManager.isDeviceManaged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceOwnerName() {
|
||||
return mDevicePolicyManager.getDeviceOwnerName();
|
||||
return mDevicePolicyManager.getDeviceOwnerNameOnAnyUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -866,10 +866,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
|
||||
mAppOps.checkPackage(callingUid, callerPackageName);
|
||||
}
|
||||
|
||||
// Check whether the caller is device owner
|
||||
// Check whether the caller is device owner, in which case we do it silently.
|
||||
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
|
||||
Context.DEVICE_POLICY_SERVICE);
|
||||
boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName);
|
||||
boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
|
||||
callerPackageName);
|
||||
|
||||
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
|
||||
statusReceiver, packageName, isDeviceOwner, userId);
|
||||
|
@ -228,7 +228,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
|
||||
final boolean forcePermissionPrompt =
|
||||
(params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
|
||||
mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
|
||||
mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
|
||||
installerPackageName);
|
||||
if ((isPermissionGranted
|
||||
|| isInstallerRoot
|
||||
|| mIsInstallerDeviceOwner)
|
||||
|
@ -13065,7 +13065,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
|
||||
try {
|
||||
if (dpm != null) {
|
||||
final ComponentName deviceOwnerComponentName = dpm.getDeviceOwner();
|
||||
final ComponentName deviceOwnerComponentName = dpm.getDeviceOwnerComponent(
|
||||
/* callingUserOnly =*/ false);
|
||||
final String deviceOwnerPackageName = deviceOwnerComponentName == null ? null
|
||||
: deviceOwnerComponentName.getPackageName();
|
||||
// Does the package contains the device owner?
|
||||
|
@ -513,7 +513,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
|
||||
Context.DEVICE_POLICY_SERVICE);
|
||||
// restricted profile can be created if there is no DO set and the admin user has no PO
|
||||
return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
|
||||
return !dpm.isDeviceManaged() && dpm.getProfileOwnerAsUser(userId) == null;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1599,7 +1599,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
DevicePolicyManager devicePolicyManager = (DevicePolicyManager)
|
||||
mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
if (devicePolicyManager == null
|
||||
|| devicePolicyManager.getDeviceOwner() == null) {
|
||||
|| !devicePolicyManager.isDeviceManaged()) {
|
||||
flags |= UserInfo.FLAG_ADMIN;
|
||||
}
|
||||
}
|
||||
|
@ -2045,9 +2045,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
private void updateDeviceOwnerLocked() {
|
||||
long ident = mInjector.binderClearCallingIdentity();
|
||||
try {
|
||||
if (getDeviceOwner() != null) {
|
||||
// TODO This is to prevent DO from getting "clear data"ed, but it should also check the
|
||||
// user id and also protect all other DAs too.
|
||||
final ComponentName deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
|
||||
if (deviceOwnerComponent != null) {
|
||||
mInjector.getIActivityManager()
|
||||
.updateDeviceOwner(getDeviceOwner().getPackageName());
|
||||
.updateDeviceOwner(deviceOwnerComponent.getPackageName());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Not gonna happen.
|
||||
@ -2248,6 +2251,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
// Build and show a warning notification
|
||||
int smallIconId;
|
||||
String contentText;
|
||||
// TODO Why does it use the DO name? The cert APIs are all for PO. b/25772443
|
||||
final String ownerName = getDeviceOwnerName();
|
||||
if (isManagedProfile(userHandle.getIdentifier())) {
|
||||
contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_administrator);
|
||||
@ -4600,22 +4604,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentName getDeviceOwner() {
|
||||
public ComponentName getDeviceOwnerComponent(boolean callingUserOnly) {
|
||||
if (!mHasFeature) {
|
||||
return null;
|
||||
}
|
||||
if (!callingUserOnly) {
|
||||
enforceManageUsers();
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!mOwners.hasDeviceOwner()) {
|
||||
return null;
|
||||
}
|
||||
if (callingUserOnly && mInjector.userHandleGetCallingUserId() !=
|
||||
mOwners.getDeviceOwnerUserId()) {
|
||||
return null;
|
||||
}
|
||||
return mOwners.getDeviceOwnerComponent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceOwnerUserId() {
|
||||
if (!mHasFeature) {
|
||||
return UserHandle.USER_NULL;
|
||||
}
|
||||
enforceManageUsers();
|
||||
synchronized (this) {
|
||||
return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "name" of the device owner. It'll work for non-DO users too, but requires
|
||||
* MANAGE_USERS.
|
||||
*/
|
||||
@Override
|
||||
public String getDeviceOwnerName() {
|
||||
if (!mHasFeature) {
|
||||
return null;
|
||||
}
|
||||
// TODO: Do we really need it? getDeviceOwner() doesn't require it.
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
|
||||
enforceManageUsers();
|
||||
synchronized (this) {
|
||||
if (!mOwners.hasDeviceOwner()) {
|
||||
return null;
|
||||
@ -4630,7 +4658,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
// Returns the active device owner or null if there is no device owner.
|
||||
@VisibleForTesting
|
||||
ActiveAdmin getDeviceOwnerAdminLocked() {
|
||||
ComponentName component = getDeviceOwner();
|
||||
ComponentName component = mOwners.getDeviceOwnerComponent();
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
@ -4659,16 +4687,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
} catch (NameNotFoundException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
if (!mOwners.hasDeviceOwner() || !getDeviceOwner().getPackageName().equals(packageName)
|
||||
|| (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
|
||||
throw new SecurityException("clearDeviceOwner can only be called by the device owner");
|
||||
}
|
||||
synchronized (this) {
|
||||
if (!mOwners.hasDeviceOwner()
|
||||
|| !mOwners.getDeviceOwnerComponent().getPackageName().equals(packageName)
|
||||
|| (mOwners.getDeviceOwnerUserId() != UserHandle.getUserId(callingUid))) {
|
||||
throw new SecurityException(
|
||||
"clearDeviceOwner can only be called by the device owner");
|
||||
}
|
||||
|
||||
final ActiveAdmin admin = getDeviceOwnerAdminLocked();
|
||||
if (admin != null) {
|
||||
admin.disableCamera = false;
|
||||
admin.userRestrictions = null;
|
||||
}
|
||||
|
||||
clearUserPoliciesLocked(new UserHandle(UserHandle.USER_SYSTEM));
|
||||
|
||||
mOwners.clearDeviceOwner();
|
||||
@ -4857,7 +4889,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
if (!mHasFeature) {
|
||||
return null;
|
||||
}
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
|
||||
enforceManageUsers();
|
||||
ComponentName profileOwner = getProfileOwner(userHandle);
|
||||
if (profileOwner == null) {
|
||||
return null;
|
||||
@ -4987,13 +5019,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceManageUsers() {
|
||||
final int callingUid = mInjector.binderGetCallingUid();
|
||||
if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceCrossUserPermission(int userHandle) {
|
||||
if (userHandle < 0) {
|
||||
throw new IllegalArgumentException("Invalid userId " + userHandle);
|
||||
}
|
||||
final int callingUid = mInjector.binderGetCallingUid();
|
||||
if (userHandle == UserHandle.getUserId(callingUid)) return;
|
||||
if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
|
||||
if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
|
||||
+ " INTERACT_ACROSS_USERS_FULL permission");
|
||||
@ -6619,8 +6658,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
|
||||
updateReceivedTime);
|
||||
|
||||
synchronized (this) {
|
||||
final String deviceOwnerPackage = getDeviceOwner() == null ? null :
|
||||
getDeviceOwner().getPackageName();
|
||||
final String deviceOwnerPackage =
|
||||
mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerComponent().getPackageName()
|
||||
: null;
|
||||
if (deviceOwnerPackage == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Pair;
|
||||
@ -35,6 +36,7 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -56,9 +58,9 @@ import static org.mockito.Mockito.when;
|
||||
*
|
||||
m FrameworksServicesTests &&
|
||||
adb install \
|
||||
-r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
|
||||
-r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
|
||||
adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
|
||||
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
|
||||
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
|
||||
|
||||
(mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
|
||||
*/
|
||||
@ -458,6 +460,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
*/
|
||||
public void testSetDeviceOwner() throws Exception {
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
@ -467,12 +470,29 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
// Make sure admin1 is installed on system user.
|
||||
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
|
||||
|
||||
// Check various get APIs.
|
||||
checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
|
||||
|
||||
// DO needs to be an DA.
|
||||
dpm.setActiveAdmin(admin1, /* replace =*/ false);
|
||||
|
||||
// Fire!
|
||||
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
|
||||
|
||||
// getDeviceOwnerComponent should return the admin1 component.
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
// Check various get APIs.
|
||||
checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
|
||||
|
||||
// getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
|
||||
|
||||
// Verify internal calls.
|
||||
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
|
||||
eq(admin1.getPackageName()));
|
||||
@ -485,7 +505,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
|
||||
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
|
||||
|
||||
assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
// Try to set a profile owner on the same user, which should fail.
|
||||
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
|
||||
@ -502,11 +522,163 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
// DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
|
||||
}
|
||||
|
||||
private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
|
||||
final int origCallingUser = mContext.binder.callingUid;
|
||||
final List origPermissions = new ArrayList(mContext.callerPermissions);
|
||||
mContext.callerPermissions.clear();
|
||||
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
|
||||
mContext.binder.callingUid = Process.SYSTEM_UID;
|
||||
|
||||
// TODO Test getDeviceOwnerName() too. To do so, we need to change
|
||||
// DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
|
||||
if (hasDeviceOwner) {
|
||||
assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
|
||||
} else {
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
|
||||
}
|
||||
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
|
||||
if (hasDeviceOwner) {
|
||||
assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
|
||||
} else {
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
|
||||
}
|
||||
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
|
||||
// Still with MANAGE_USERS.
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
if (hasDeviceOwner) {
|
||||
assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
|
||||
} else {
|
||||
assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
|
||||
}
|
||||
|
||||
mContext.binder.callingUid = Process.SYSTEM_UID;
|
||||
mContext.callerPermissions.remove(permission.MANAGE_USERS);
|
||||
// System can still call "OnAnyUser" without MANAGE_USERS.
|
||||
if (hasDeviceOwner) {
|
||||
assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
|
||||
} else {
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
|
||||
}
|
||||
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
|
||||
// Still no MANAGE_USERS.
|
||||
if (hasDeviceOwner) {
|
||||
assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
} else {
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
}
|
||||
|
||||
try {
|
||||
dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerComponentOnAnyUser();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerUserId();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerNameOnAnyUser();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
|
||||
// Still no MANAGE_USERS.
|
||||
assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
|
||||
assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
|
||||
assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
|
||||
|
||||
try {
|
||||
dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerComponentOnAnyUser();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerUserId();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
try {
|
||||
dpm.getDeviceOwnerNameOnAnyUser();
|
||||
fail();
|
||||
} catch (SecurityException expected) {
|
||||
}
|
||||
|
||||
// Restore.
|
||||
mContext.binder.callingUid = origCallingUser;
|
||||
mContext.callerPermissions.addAll(origPermissions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
|
||||
*/
|
||||
public void testSetDeviceOwner_noSuchPackage() {
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
@ -528,6 +700,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
|
||||
public void testClearDeviceOwner() throws Exception {
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
@ -547,7 +720,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
|
||||
eq(admin1.getPackageName()));
|
||||
|
||||
assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
// Set up other mocks.
|
||||
when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
|
||||
@ -559,13 +732,14 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
dpm.clearDeviceOwnerApp(admin1.getPackageName());
|
||||
|
||||
// Now DO shouldn't be set.
|
||||
assertNull(dpm.getDeviceOwner());
|
||||
assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
// TODO Check other calls.
|
||||
}
|
||||
|
||||
public void testClearDeviceOwner_fromDifferentUser() throws Exception {
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
@ -585,7 +759,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
|
||||
eq(admin1.getPackageName()));
|
||||
|
||||
assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
|
||||
assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
|
||||
|
||||
// Now call clear from the secondary user, which should throw.
|
||||
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
|
||||
@ -601,8 +775,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
|
||||
}
|
||||
|
||||
// Now DO shouldn't be set.
|
||||
assertNotNull(dpm.getDeviceOwner());
|
||||
// DO shouldn't be removed.
|
||||
assertTrue(dpm.isDeviceManaged());
|
||||
}
|
||||
|
||||
public void testSetProfileOwner() throws Exception {
|
||||
@ -639,6 +813,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
|
||||
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
@ -667,8 +842,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
|
||||
assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
|
||||
|
||||
// Make sure it's set.
|
||||
assertEquals(admin2, dpm.getDeviceOwnerComponent());
|
||||
assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
|
||||
|
||||
// Then check getDeviceOwnerAdminLocked().
|
||||
assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
|
||||
@ -692,7 +866,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
dpms.mOwners.writeDeviceOwner();
|
||||
|
||||
// Make sure the DO component name doesn't have a class name.
|
||||
assertEquals("", dpms.getDeviceOwner().getClassName());
|
||||
assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
|
||||
|
||||
// Then create a new DPMS to have it load the settings from files.
|
||||
when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
|
||||
@ -702,7 +876,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
// Now the DO component name is a full name.
|
||||
// *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
|
||||
// DO.
|
||||
assertEquals(admin1, dpms.getDeviceOwner());
|
||||
assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
|
||||
}
|
||||
|
||||
public void testSetGetApplicationRestriction() {
|
||||
@ -740,6 +914,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
|
||||
public void testSetUserRestriction_asDo() throws Exception {
|
||||
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_USERS);
|
||||
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
|
||||
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
|
||||
|
||||
|
Reference in New Issue
Block a user