1. 程式人生 > >Android 裝置管理器和有權檢視使用情況的應用詳解

Android 裝置管理器和有權檢視使用情況的應用詳解

Android中有很多的應用想要取得裝置管理器許可權,成為系統裝置管理器之後可以實現鎖屏、擦除使用者資料等功能,專案中客戶希望自己的app能夠預設成為系統的裝置管理器,如何操作呢?,下面來介紹一下:

        DevicePolicyManager mDPM = (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
        if(!mDPM.isAdminActive(new ComponentName(PkgName,ClassName))){
            mDPM.setActiveAdmin(new ComponentName(PkgName,ClassName), false);
        }

首先獲取DevicePolicyManager,然後通過DevicePolicyManager的isAdminActive方法判斷當前要設定的應用是否已經是預設的裝置管理器.如果不是的話,通過DevicePolicyManager的setActiveAdmin方法將它設定為預設裝置管理器.

下面來看看DevicePolicyManager的isAdminActive方法具體做了什麼,DevicePolicyManager的isAdminActive方法最終呼叫的是DevicePolicyManagerService的isAdminActive;

    @Override
    public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
        if (!mHasFeature) {
            return false;
        }
        enforceFullCrossUsersPermission(userHandle);    //檢查呼叫者許可權
        synchronized (this) {    //加了程序鎖,防止阻塞
            return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;    //呼叫系統的getActiveAdminUncheckedLocked方法
        }
    }

接下來去看看getActiveAdminUncheckedLocked方法:

    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
        ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);    //通過當前應用的componentName來得到一個ActiveAdmin物件
        if (admin != null
                && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
                && who.getClassName().equals(admin.info.getActivityInfo().name)) {
            return admin;
        }
        return null;
    }

getActiveAdminUncheckedLocked中通過getUserData(userHandle).mAdminMap.get(who)獲取一個ActiveAdmin物件,

由於Android是支援多使用者的,所以通過getUserData(userHandle)獲取當前使用者資料,預設的使用者UserId是0,mAdminMap是一個ArrayMap, 系統中的宣告是ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>();

如果判斷不是預設裝置管理器就會呼叫DevicePolicyManager的setActiveAdmin方法

 /**
     * @param adminReceiver The admin to add
     * @param refreshing true = update an active admin, no error
     */
    @Override
    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
        if (!mHasFeature) {
            return;
        }
        setActiveAdmin(adminReceiver, refreshing, userHandle, null);    //這裡呼叫的是私有方法setActiveAdmin
    }

 private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
            Bundle onEnableData) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);    //許可權檢查,這裡檢查的是使用者是否有android.Manifest.permission.MANAGE_DEVICE_ADMINS許可權,這個許可權是需要簽名許可權或者priv-app下的應用才能使用
        enforceFullCrossUsersPermission(userHandle);    //許可權檢查,這裡檢查的是不同使用者之間的許可權

        DevicePolicyData policy = getUserData(userHandle);    //獲取當前使用者的DevicePolicyData
        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
                /* throwForMissionPermission= */ true);    //獲取當前使用者的ComponentName獲取DeviceAdminInfo
        if (info == null) {
            throw new IllegalArgumentException("Bad admin: " + adminReceiver);
        }
        if (!info.getActivityInfo().applicationInfo.isInternal()) {
            throw new IllegalArgumentException("Only apps in internal storage can be active admin: "
                    + adminReceiver);
        }
        synchronized (this) {
            long ident = mInjector.binderClearCallingIdentity();
            try {
                final ActiveAdmin existingAdmin
                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);    //取出系統當前預設的裝置管理器
                if (!refreshing && existingAdmin != null) {
                    throw new IllegalArgumentException("Admin is already added");    //如果refreshing為false,並且不存在預設裝置管理器,直接報錯~
                }
                if (policy.mRemovingAdmins.contains(adminReceiver)) {    //如果設定當前使用者DevicePolicyData中已經移除過的裝置管理器,直接報錯
                    throw new IllegalArgumentException(
                            "Trying to set an admin which is being removed");
                }
                ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);    //新建立一個裝置管理器
                newAdmin.testOnlyAdmin =
                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin
                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);
                policy.mAdminMap.put(adminReceiver, newAdmin);    //把componentName和ActiveAdmin放到當前使用者的DevicePolicyData的ArrayMap中
                int replaceIndex = -1;
                final int N = policy.mAdminList.size();    //獲取當前DevicePolicyData中的mAdminList的大小
                for (int i=0; i < N; i++) {
                    ActiveAdmin oldAdmin = policy.mAdminList.get(i);
                    if (oldAdmin.info.getComponent().equals(adminReceiver)) {    //找到預設裝置管理器的位置,並將位置標記
                        replaceIndex = i;
                        break;
                    }
                }
                if (replaceIndex == -1) {
                    policy.mAdminList.add(newAdmin);    //如果替換位置沒有找到,新增新的AdminActive到mAdminList中
                    enableIfNecessary(info.getPackageName(), userHandle);
                } else {
                    policy.mAdminList.set(replaceIndex, newAdmin);    //如果替換位置已經找到,就將當前的ActiveAdmin插入到該位置,替換為新的預設裝置管理器
                }
                saveSettingsLocked(userHandle);    //儲存當前使用者的設定
                sendAdminCommandLocked(newAdmin,     DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                        onEnableData, null);    //傳送通知給新的預設裝置管理器
            } finally {
                mInjector.binderRestoreCallingIdentity(ident);
            }
        }
    }