您的位置:首页 > 其它

BasicManageProfile申请设备管理user的流程分析

2017-10-24 09:16 706 查看
上篇双开中提及了BasicManagedProfile demo,本文分析下demo中申请manage profile user的流程

development/samples/browseable/BasicManagedProfile/src/com/example/android/basicmanagedprofile/SetupProfileFragment.java

private void provisionManagedProfile() {
...
Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
activity.getApplicationContext().getPackageName());
...
startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
...
}
demo中的代码特别简单,就是发送intent就完了。后续流程会跳转到ManagedProvisioning.apk

源码位于packages/apps/ManagedProvisioning,这个apk个人理解是DevicePolicyManager的UI层面。

<activity
android:name=".uiflows.PreProvisioningActivity"
android:excludeFromRecents="true"
android:immersive="true"
android:launchMode="singleTop"
android:theme="@style/SetupWorkSpaceTheme">
<intent-filter android:priority="10">
<action android:name="android.app.action.PROVISION_MANAGED_PROFILE" />
<action android:name="android.app.action.PROVISION_MANAGED_USER" />
<action android:name="android.app.action.PROVISION_MANAGED_DEVICE" />
<action android:name="android.app.action.PROVISION_MANAGED_SHAREABLE_DEVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
从AndroidManifest中看到入口在PreProvisioningActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mController = new PreProvisioningController(
this,
this);

mController.initiateProvisioning(getIntent(), getCallingPackage());
}
跳转到PreProvisioningController.java中

public void initiateProvisioning(Intent intent, String callingPackage) {
...

mIsProfileOwnerProvisioning = mUtils.isProfileOwnerAction(mParams.provisioningAction);
...

// Initiate the corresponding provisioning mode
if (mIsProfileOwnerProvisioning) {
initiateProfileOwnerProvisioning(intent);
} else {
initiateDeviceOwnerProvisioning(intent);
}
}
这里mIsProfileOwnerProvisioning=true

private void initiateProfileOwnerProvisioning(Intent intent) {
mUi.initiateUi(
R.string.setup_work_profile,
R.string.setup_profile_start_setup,
R.string.company_controls_workspace,
R.string.the_following_is_your_mdm,
mParams);

// If there is already a managed profile, setup the profile deletion dialog.
int existingManagedProfileUserId = mUtils.alreadyHasManagedProfile(mContext);
if (existingManagedProfileUserId != -1) {
ComponentName mdmPackageName = mDevicePolicyManager
.getProfileOwnerAsUser(existingManagedProfileUserId);
String domainName = mDevicePolicyManager
.getProfileOwnerNameAsUser(existingManagedProfileUserId);
mUi.showDeleteManagedProfileDialog(mdmPackageName, domainName,
existingManagedProfileUserId);
}
}
代码主要分为两部分,第一个是初始化UI,第二个是如果系统中已有manage profile user的话,会先弹出删除当前manage profile user的UI,这里看出manage profile user只可以有一个

mUi实际上是PreProvisioningActivity

public void initiateUi(int headerRes, int titleRes, int consentRes, int mdmInfoRes,
ProvisioningParams params) {
// Setup the UI.
initializeLayoutParams(R.layout.user_consent, headerRes, false);
Button nextButton = (Button) findViewById(R.id.setup_button);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mController.afterNavigateNext();
}
});
...
}
全部是UI的初始化代码,这个时候Activity就会等待用户点击唯一的按键继续后续流程

public void afterNavigateNext() {
...
mUi.showUserConsentDialog(mParams, mIsProfileOwnerProvisioning);
...
}
@Override
public void showUserConsentDialog(ProvisioningParams params,
boolean isProfileOwnerProvisioning) {
UserConsentDialog dialog;
if (isProfileOwnerProvisioning) {
dialog = UserConsentDialog.newProfileOwnerInstance();
} else {
dialog = UserConsentDialog.newDeviceOwnerInstance(!params.startedByTrustedSource);
}
dialog.show(getFragmentManager(), "UserConsentDialogFragment");
}
中间又是dialog的相关代码,这个太熟悉的不贴代码了,在dailog的点击事件中进行后续处理

@Override
public void onDialogConsent() {
...

mController.continueProvisioningAfterUserConsent();
}
后续一路跳转会到

@Override
public void startProfileOwnerProvisioning(ProvisioningParams params) {
Intent intent = new Intent(this, ProfileOwnerProvisioningActivity.class);
intent.putExtra(ProvisioningParams.EXTRA_PROVISIONING_PARAMS, params);
startActivityForResult(intent, PROVISIONING_REQUEST_CODE);
// Set cross-fade transition animation into the interstitial progress activity.
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
跳转到另一个Activity ProfileOwnerProvisioningActivity

@Override
protected void onResume() {
...

// Start service async to make sure the UI is loaded first.
final Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(ProfileOwnerProvisioningActivity.this,
ProfileOwnerProvisioningService.class);
intent.putExtras(getIntent());
startService(intent);
}
});
}
在onResume中启动了进行真正工作的Service ProfileOwnerProvisioningService

private class RunnerTask extends AsyncTask<Intent, Void, Void> {
@Override
protected Void doInBackground(Intent ... intents) {
...
initialize(intents[0]);
startManagedProfileOrUserProvisioning();
...
}
}
在onStartCommand中启动了自定义的异步任务

private void startManagedProfileOrUserProvisioning() throws ProvisioningException {

ProvisionLogger.logd("Starting managed profile or user provisioning");

if(isProvisioningManagedUser()) {
mManagedProfileOrUserInfo = mUserManager.getUserInfo(mUserManager.getUserHandle());
if(mManagedProfileOrUserInfo == null) {
throw raiseError("Couldn't get current user information");
}
} else {
// Work through the provisioning steps in their corresponding order
//代码流程会走到这里,创建profile user
createProfile(getString(R.string.default_managed_profile_name));
}
if (mManagedProfileOrUserInfo != null) {
final DeleteNonRequiredAppsTask deleteNonRequiredAppsTask; //删除新user不需要的app
final DisableInstallShortcutListenersTask disableInstallShortcutListenersTask; //禁止新user创建快捷方式
final DisableBluetoothSharingTask disableBluetoothSharingTask; //禁止蓝牙分享功能
final ManagedProfileSettingsTask managedProfileSettingsTask =
new ManagedProfileSettingsTask(this, mManagedProfileOrUserInfo.id);
//设置SettingProvider中的MANAGED_PROFILE_CONTACT_REMOTE_SEARCH字段,该字段功能详细可见
//packages/providers/ContactsProvider/src/com/android/providers/contacts/enterprise/EnterprisePolicyGuard.java
//能控制跨user查询联系人数据库的行为。

disableInstallShortcutListenersTask = new DisableInstallShortcutListenersTask(this,
mManagedProfileOrUserInfo.id);
disableBluetoothSharingTask = new DisableBluetoothSharingTask(
mManagedProfileOrUserInfo.id);
// TODO Add separate set of apps for MANAGED_USER, currently same as of DEVICE_OWNER.
deleteNonRequiredAppsTask = new DeleteNonRequiredAppsTask(this,
mParams.deviceAdminComponentName.getPackageName(),
(isProvisioningManagedUser() ? DeleteNonRequiredAppsTask.MANAGED_USER
: DeleteNonRequiredAppsTask.PROFILE_OWNER),
true /* creating new profile */,
mManagedProfileOrUserInfo.id, false /* delete non-required system apps */,
new DeleteNonRequiredAppsTask.Callback() {

@Override
public void onSuccess() {
// Need to explicitly handle exceptions here, as
// onError() is not invoked for failures in
// onSuccess().
try {
disableBluetoothSharingTask.run();
if (!isProvisioningManagedUser()) {
managedProfileSettingsTask.run();
disableInstallShortcutListenersTask.run();
}
setUpUserOrProfile();
} catch (ProvisioningException e) {
error(e.getMessage(), e);
} catch (Exception e) {startManagedProfileOrUserProvisioning
error("Provisioning failed", e);
}
finish();
}

@Override
public void onError() {
// Raise an error with a tracing exception attached.
error("Delete non required apps task failed.", new Exception());
finish();
}
});

deleteNonRequiredAppsTask.run();
}
}


这里先看下createProfile

private void createProfile(String profileName) throws ProvisioningException {

ProvisionLogger.logd("Creating managed profile with name " + profileName);

mManagedProfileOrUserInfo = mUserManager.createProfileForUser(profileName,
UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_DISABLED,
Process.myUserHandle().getIdentifier());

if (mManagedProfileOrUserInfo == null) {
throw raiseError("Couldn't create profile.");
}
}


该方法就是调用UserManager创建了profile user,接下来走到setUpUserOrProfile

private void setUpUserOrProfile() throws ProvisioningException {
installMdmOnManagedProfile(); //创建BasicManagedProfile应用到新创建的user
setMdmAsActiveAdmin();  //设置BasicManagedProfile应用为当前的admin
setMdmAsManagedProfileOwner(); //设置BasicManagedProfile应用为profile user owner

if (!isProvisioningManagedUser()) {
setOrganizationColor();
setDefaultUserRestrictions();  //设置默认的限制,其实只有一条,就是不能更换壁纸
CrossProfileIntentFiltersHelper.setFilters( //使intent跨user使用的关键方法
getPackageManager(), getUserId(), mManagedProfileOrUserInfo.id);
if (!startManagedProfile(mManagedProfileOrUserInfo.id)) { //真正切换用户的方法
throw raiseError("Could not start user in background");
}
// Wait for ACTION_USER_UNLOCKED to be sent before trying to migrate the account.
// Even if no account is present, we should not send the provisioning complete broadcast
// before the managed profile user is properly started.
if ((mUnlockedReceiver != null) && !mUnlockedReceiver.waitForUserUnlocked()) {
return; //等待user创建完毕并为解锁状态,正常状况下不会走return
}

// Note: account migration must happen after setting the profile owner.
// Otherwise, there will be a time interval where some apps may think that the account
// does not have a profile owner.
//account在user间的迁移,对于BasicManagedProfile来说accountToMigrate是null
mUtils.maybeCopyAccount(this, mParams.accountToMigrate, Process.myUserHandle(),
mManagedProfileOrUserInfo.getUserHandle());
}
}

代码行数不多是因为基本每一行都是另一个方法的调用,其实做了大量的工作,整个app中到处使用的缩写mdm,展开是mobile device management application (MDM).

private boolean startManagedProfile(int userId)  {
ProvisionLogger.logd("Starting user in background");
IActivityManager iActivityManager = ActivityManagerNative.getDefault();
// Register a receiver for the Intent.ACTION_USER_UNLOCKED to know when the managed profile
// has been started and unlocked.
mUnlockedReceiver = new UserUnlockedReceiver(this, userId);
//接受user启动并解锁消息的Receiver,以便后续操作
try {
return iActivityManager.startUserInBackground(userId); //切换user到刚创建的profile user
} catch (RemoteException neverThrown) {
// Never thrown, as we are making local calls.
ProvisionLogger.loge("This should not happen.", neverThrown);
}
return false;
}

最终切换到刚创建的用户,整个流程结束。

从整个流程看PackageManagerService,ActivityManagerService,UserManagerService和DevicePolicyManager几个之间耦合的挺紧的,例如代码中AsUser为后缀的的各种方法肯定和UserManagerService相关;切换、启动,停止用户代码却不在UserManagerService中,而是在ActivityManagerService中;用户切换app的控制要通过PackageManagerService来完成;PackageManagerService最核心的工作是创建一个profile
user。要想彻底搞懂它们之间的关系,四个服务都要看呀,想想PackageManagerService.java就有21000+行...感到压力山大
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息