关于android的设备管理器-DevicePolicyManager(一)

来源:互联网 发布:淘宝双十一活动时间表 编辑:程序博客网 时间:2024/05/17 06:43

    在Andorid的设置->安全里面有个设备管理器的选项,相信大部分android用户都不太会去注意这个东西,最近在安装了一个应用之后发现这个里面的东西变了,怎么回事呢,研究研究看看。</span>

        老思路,从已有的最明显的线索开始分析,“设备管理器”这几个字就是最好的线索,在Setting的package里面搜搜,一大堆多语言话的字符串,这个不是我要找的,我要找的是谁在用这个字符串,在一个布局文件里找到了:

res/xml/security_settings.xml

        <Preference android:title="@string/manage_device_admin"                    android:summary="@string/manage_device_admin_summary"                    android:persistent="false"                    android:fragment="com.android.settings.DeviceAdminSettings"/>
那就要具体看DeviceAdminSettings这个fragment了。这是一个比较正规的fragment,很容易理解,关键在其中的updateList这个函数:

    void updateList() {        mActiveAdmins.clear();        List<ComponentName> cur = mDPM.getActiveAdmins();        if (cur != null) {            for (int i=0; i<cur.size(); i++) {                mActiveAdmins.add(cur.get(i));            }        }        mAvailableAdmins.clear();        List<ResolveInfo> avail = getActivity().getPackageManager().queryBroadcastReceivers(                new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),                PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);        if (avail == null) {            avail = Collections.emptyList();        }        // Some admins listed in mActiveAdmins may not have been found by the above query.        // We thus add them separately.        Set<ComponentName> activeAdminsNotInAvail = new HashSet<ComponentName>(mActiveAdmins);        for (ResolveInfo ri : avail) {            ComponentName riComponentName =                    new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);            activeAdminsNotInAvail.remove(riComponentName);        }        if (!activeAdminsNotInAvail.isEmpty()) {            avail = new ArrayList<ResolveInfo>(avail);            PackageManager packageManager = getActivity().getPackageManager();            for (ComponentName unlistedActiveAdmin : activeAdminsNotInAvail) {                List<ResolveInfo> resolved = packageManager.queryBroadcastReceivers(                        new Intent().setComponent(unlistedActiveAdmin),                        PackageManager.GET_META_DATA                                | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);                if (resolved != null) {                    avail.addAll(resolved);                }            }        }        for (int i = 0, count = avail.size(); i < count; i++) {            ResolveInfo ri = avail.get(i);            try {                DeviceAdminInfo dpi = new DeviceAdminInfo(getActivity(), ri);                if (dpi.isVisible() || mActiveAdmins.contains(dpi.getComponent())) {                    mAvailableAdmins.add(dpi);                }            } catch (XmlPullParserException e) {                Log.w(TAG, "Skipping " + ri.activityInfo, e);             } catch (IOException e) {                Log.w(TAG, "Skipping " + ri.activityInfo, e);             }        }            getListView().setAdapter(new PolicyListAdapter());    }
这个函数本身不复杂,但是还是看不出来所谓的设备管理器是个什么东东。这里的线索就需要仔细分析了,这里貌似有两个列表:

一个Active的列表和一个Available的列表,ok。和在UI上看到的确实是一致的。那么可以说明列表的每个项应该就是一个所谓的 设备管理器,两个列表的差别就是是否是active的。

那就看看Active的列表,它是怎么来的呢:

        mActiveAdmins.clear();        List<ComponentName> cur = mDPM.getActiveAdmins();        if (cur != null) {            for (int i=0; i<cur.size(); i++) {                mActiveAdmins.add(cur.get(i));            }        }
ok,从mDPM里get的,mDPM是DevicePolicyManager对象。看到这里要吐槽下了,android的framework里XXXManager基本都是会对应一个XXXService的,都是通过典型的AIDL来实现的进程间的通信。这里也不错所料:

    /**     * Return a list of all currently active device administrator's component     * names.  Note that if there are no administrators than null may be     * returned.     */    public List<ComponentName> getActiveAdmins() {        if (mService != null) {            try {                return mService.getActiveAdmins(UserHandle.myUserId());            } catch (RemoteException e) {                Log.w(TAG, "Failed talking with device policy service", e);            }        }        return null;    }

mService必然是IDevicePolicyManager的对象,要找具体实现肯定要找到具体的service,DevicePolicyManagerService。

    public List<ComponentName> getActiveAdmins(int userHandle) {        enforceCrossUserPermission(userHandle);        synchronized (this) {            DevicePolicyData policy = getUserData(userHandle);            final int N = policy.mAdminList.size();            if (N <= 0) {                return null;            }            ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);            for (int i=0; i<N; i++) {                res.add(policy.mAdminList.get(i).info.getComponent());            }            return res;        }    }
首先看到enforceCrossUserPermission这个应该是要求权限的,很多Service的方法都会先检查权限,这是Android安全机制的一种体现,不多说这个了。看逻辑是比较简单的,从本地的List里面复制了一份给返回。

看到这里,还是不知道这个东西到底是什么,但至少知道他是以一个list的形式保存在这个service里面的,那就看怎么来add这个list吧。

在这个文件里就找到了两处add:一处在 setActiveAdmin,一致在 loadSettingsLocked 

最踪下setActiveAdmin发现他是一个hide的借口存在于Manager类上,看来第三发的应该是不能调到的,那就看loadSettingsLocked吧。不能看到这个函数里面在做xml的parser,那么大概可以猜到了,应该是有一个xml的文件存在的。

    private static JournaledFile makeJournaledFile(int userHandle) {        final String base = userHandle == 0                ? "/data/system/" + DEVICE_POLICIES_XML                : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)                        .getAbsolutePath();        return new JournaledFile(new File(base), new File(base + ".tmp"));    }
查看这个函数就大概找到了。/data/system下device_policies.xml 具体先不看这个xml的内容,我们关心的是谁回去写这个文件呢?与他对应有个saveSettingsLocked,追踪它可以发现,在handlePackagesChanged里面调用了,其他有很多调用,但是看起来不像。

可以发现时在package发生变化的时候调用到的,那之前看到在有新应用安装以后page发生变化,这个现象也是符合的。


现象是解释通了,但是还是不明白,它到底是干什么用的。下回再分析吧。










0 0
原创粉丝点击