Android DPC模式多开 APP
1、修改创建多个profile时超出限制
packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/preprovisioning/PreProvisioningController.java
// PO preconditions
if (isProfileOwnerProvisioning()) {
// If there is already a managed profile, first check it may be removed.
// If so, setup the profile deletion dialog.
int existingManagedProfileUserId = mUtils.alreadyHasManagedProfile(mContext);
if (existingManagedProfileUserId > mUserManager.getMaxSupportedUsers()) { // 修改支持多个
if (isRemovingManagedProfileDisallowed()) {
mUi.showErrorAndClose(R.string.cant_replace_or_remove_work_profile,
R.string.work_profile_cant_be_added_contact_admin,
"Cannot remove existing work profile");
} else {
ComponentName mdmPackageName = mDevicePolicyManager
.getProfileOwnerAsUser(existingManagedProfileUserId);
String domainName = mDevicePolicyManager
.getProfileOwnerNameAsUser(existingManagedProfileUserId);
mUi.showDeleteManagedProfileDialog(mdmPackageName, domainName,
existingManagedProfileUserId);
}
return;
}
}
2、修改创建profile的任务:
packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/provisioning/ProfileOwnerProvisioningController.java
private void setUpTasksManagedProfile() {
if(Utils.alreadyHasManagedProfile() == -1) {
addTasks(
new CreateManagedProfileTask(mContext, mParams, this),
new InstallExistingPackageTask(mParams.inferDeviceAdminPackageName(), mContext,
mParams, this),
new SetDevicePolicyTask(mContext, mParams, this),
new ManagedProfileSettingsTask(mContext, mParams, this),
new DisableInstallShortcutListenersTask(mContext, mParams, this),
new StartManagedProfileTask(mContext, mParams, this),
new CopyAccountToUserTask(mParentUserId, mContext, mParams, this));
}
else {
addTasks(
new CreateManagedProfileTask(mContext, mParams, this),
new ManagedProfileSettingsTask(mContext, mParams, this),
new DisableInstallShortcutListenersTask(mContext, mParams, this),
new StartManagedProfileTask(mContext, mParams, this),
new CopyAccountToUserTask(mParentUserId, mContext, mParams, this));
}
}
修改 markUserProvisioningStateInitiallyDone
packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/finalization/UserProvisioningStateHelper.java
if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
// Managed profiles are a special case as two users are involved.
managedProfileUserId = mUtils.getLastManagedProfile(mContext).getIdentifier(); // 这里改成 getLastManagedProfile
if (userSetupCompleted) {
// SUW on current user is complete, so nothing much to do beyond indicating we're
// all done.
newProfileState = STATE_USER_SETUP_FINALIZED;
} else {
// We're still in SUW, so indicate that a managed-profile was setup on current user,
// and that we're awaiting finalization on both.
newState = STATE_USER_PROFILE_COMPLETE;
newProfileState = STATE_USER_SETUP_COMPLETE;
}
}
// 新增如下:
public UserHandle getLastManagedProfile(Context context) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
int currentUserId = userManager.getUserHandle();
UserInfo tmp;
List<UserInfo> userProfiles = userManager.getProfiles(currentUserId);
for (UserInfo profile : userProfiles) {
if (profile.isManagedProfile()) {
tmp = profile;
}
}
if(tmp != null) return new UserHandle(tmp.id);
return null;
}
3、修改 mUserManager.getMaxSupportedUsers
frameworks/base/core/java/android/os/UserManager.java
@UnsupportedAppUsage
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
return 100;
// if (android.os.Build.ID.startsWith("JVP")) return 1;
// return SystemProperties.getInt("fw.max_users",
// Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
4、修改 UserManagerService canAddMoreProfilesToUser getMaxUsersOfTypePerParent
frameworks/base/services/core/java/com/android/server/pm/UserManagerService.java
@VisibleForTesting
int getMaxUsersOfTypePerParent(String userType) {
return UserManager.getMaxSupportedUsers();
// final UserTypeDetails type = mUserTypes.get(userType);
// if (type == null) {
// return 0;
// }
// return getMaxUsersOfTypePerParent(type);
}
private static int getMaxUsersOfTypePerParent(UserTypeDetails userTypeDetails) {
return UserManager.getMaxSupportedUsers();
// final int defaultMax = userTypeDetails.getMaxAllowedPerParent();
// if (!Build.IS_DEBUGGABLE) {
// return defaultMax;
// } else {
// if (userTypeDetails.isManagedProfile()) {
// return SystemProperties.getInt("persist.sys.max_profiles", defaultMax);
// }
// }
// return defaultMax;
}
5、修改 Settings createNewUserLI :
frameworks/base/services/core/java/com/android/server/pm/Settings.java
for (int i = 0; i < packagesCount; i++) {
PackageSetting ps = packagesIterator.next();
if (ps.pkg == null) {
continue;
}
final boolean shouldMaybeInstall = ps.isSystem() &&
!ArrayUtils.contains(disallowedPackages, ps.name) &&
!ps.getPkgState().isHiddenUntilInstalled();
final boolean shouldReallyInstall = (shouldMaybeInstall &&
(skipPackageWhitelist || userTypeInstallablePackages.contains(ps.name))) || InExcludeList(ps.name); //设置要安装的包名列表
// Only system apps are initially installed.
ps.setInstalled(shouldReallyInstall, userHandle);
// If userTypeInstallablePackages is the *only* reason why we're not installing,
// then uninstallReason is USER_TYPE. If there's a different reason, or if we
// actually are installing, put UNKNOWN.
final int uninstallReason = (shouldMaybeInstall && !shouldReallyInstall) ?
UNINSTALL_REASON_USER_TYPE : UNINSTALL_REASON_UNKNOWN;
ps.setUninstallReason(uninstallReason, userHandle);
if (!shouldReallyInstall) {
writeKernelMappingLPr(ps);
}
6、修改 setProfileEnabled 和 setUserProvisioningState:
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@Override
public void setProfileEnabled(ComponentName who) {
if (!mHasFeature) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
synchronized (getLockObject()) {
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
final int userId = UserHandle.getCallingUserId();
enforceManagedProfile(userId, "enable the profile");
// Check if the profile is already enabled.
// UserInfo managedProfile = getUserInfo(userId);
// if (managedProfile.isEnabled()) {
// Slog.e(LOG_TAG,
// "setProfileEnabled is called when the profile is already enabled");
// return;
// }
for (UserInfo userInfo : mUserManager.getProfiles(callingUserId)) {
if (!userInfo.isEnabled()) {
mInjector.binderWithCleanCallingIdentity(() -> {
int identifier = userInfo.id;
mUserManager.setUserEnabled(identifier);
UserInfo parent = mUserManager.getProfileParent(identifier);
Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
intent.putExtra(Intent.EXTRA_USER, new UserHandle(identifier));
UserHandle parentHandle = new UserHandle(parent.id);
mLocalService.broadcastIntentToCrossProfileManifestReceiversAsUser(intent,
parentHandle, /* requiresPermission= */ true);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, parentHandle);
});
}
}
}
}
@Override
public void setUserProvisioningState(int newState, int userHandle) {
if (!mHasFeature) {
return;
}
if (userHandle != mOwners.getDeviceOwnerUserId() && !mOwners.hasProfileOwner(userHandle)
&& getManagedUserId(userHandle) == -1) {
// No managed device, user or profile, so setting provisioning state makes no sense.
throw new IllegalStateException("Not allowed to change provisioning state unless a "
+ "device or profile owner is set.");
}
synchronized (getLockObject()) {
boolean transitionCheckNeeded = false; //改为false不检查
// Calling identity/permission checks.
if (isAdb()) {
// ADB shell can only move directly from un-managed to finalized as part of directly
// setting profile-owner or device-owner.
if (getUserProvisioningState(userHandle) !=
DevicePolicyManager.STATE_USER_UNMANAGED
|| newState != DevicePolicyManager.STATE_USER_SETUP_FINALIZED) {
throw new IllegalStateException("Not allowed to change provisioning state "
+ "unless current provisioning state is unmanaged, and new state is "
+ "finalized.");
}
transitionCheckNeeded = false;
} else {
// For all other cases, caller must have MANAGE_PROFILE_AND_DEVICE_OWNERS.
enforceCanManageProfileAndDeviceOwners();
}
final DevicePolicyData policyData = getUserData(userHandle);
if (transitionCheckNeeded) {
// Optional state transition check for non-ADB case.
checkUserProvisioningStateTransition(policyData.mUserProvisioningState, newState);
}
policyData.mUserProvisioningState = newState;
saveSettingsLocked(userHandle);
}
}
7、 删除不需要的APP
默认情况下创建完用户会安装 Contacts 、 Files 等APP,其定义在:
frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
getNonRequiredApps
@NonNull
public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
@NonNull String provisioningAction) {
final Set<String> nonRequiredApps = getLaunchableApps(userId);
// Newly installed system apps are uninstalled when they are not required and are either
// disallowed or have a launcher icon.
//nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName())); //将需要的APP删除,即安装这些需要的APP,注释即不安装
nonRequiredApps.removeAll(getSystemInputMethods(userId)); //默认安装输入法
nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
return nonRequiredApps;
}
private Set<String> getRequiredApps(String provisioningAction, String dpcPackageName) {
final Set<String> requiredApps = new ArraySet<>();
requiredApps.addAll(getRequiredAppsSet(provisioningAction));
requiredApps.addAll(getVendorRequiredAppsSet(provisioningAction));
requiredApps.add(dpcPackageName);
return requiredApps;
}
private Set<String> getRequiredAppsSet(String provisioningAction) {
final int resId;
switch (provisioningAction) {
case ACTION_PROVISION_MANAGED_USER:
resId = R.array.required_apps_managed_user;
break;
case ACTION_PROVISION_MANAGED_PROFILE:
resId = R.array.required_apps_managed_profile;
break;
case ACTION_PROVISION_MANAGED_DEVICE:
resId = R.array.required_apps_managed_device;
break;
default:
throw new IllegalArgumentException("Provisioning type "
+ provisioningAction + " not supported.");
}
return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
}
private Set<String> getVendorRequiredAppsSet(String provisioningAction) {
final int resId;
switch (provisioningAction) {
case ACTION_PROVISION_MANAGED_USER:
resId = R.array.vendor_required_apps_managed_user;
break;
case ACTION_PROVISION_MANAGED_PROFILE:
resId = R.array.vendor_required_apps_managed_profile;
break;
case ACTION_PROVISION_MANAGED_DEVICE:
resId = R.array.vendor_required_apps_managed_device;
break;
default:
throw new IllegalArgumentException("Provisioning type "
+ provisioningAction + " not supported.");
}
return new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(resId)));
}
上述默认需安装的APP定义如下:
frameworks/base/core/res/res/values/required_apps_managed_profile.xml
<resources>
<!-- A list of apps to be retained in the managed profile.
Takes precedence over the disallowed apps lists. -->
<string-array translatable="false" name="required_apps_managed_profile">
<item>com.android.contacts</item>
<item>com.android.settings</item>
<item>com.android.providers.downloads</item>
<item>com.android.providers.downloads.ui</item>
<item>com.android.documentsui</item>
</string-array>
</resources>