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

上篇双开中提及了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

扫描二维码关注公众号,回复: 3742325 查看本文章

   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+行...感到压力山大

猜你喜欢

转载自blog.csdn.net/firedancer0089/article/details/78325756
今日推荐