關於android的設備管理器-DevicePolicyManager(一)


    在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。非常easy理解。關鍵在當中的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發生變化,這個現象也是符合的。


現象是解釋通了,可是還是不明確,它究竟是干什么用的。下回再分析吧。











免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM