Android之Lollipop DevicePolicyManager学习(上)
Android 5.0(lollipop)發(fā)布之后,看特性文檔增加了不少有趣的東西。
最近花了一些時(shí)間,研究了下其中Managed Profile的概念,簡(jiǎn)稱MP,記錄下來(lái)作為一些經(jīng)驗(yàn),有需要的同學(xué)請(qǐng)參考。
?
簡(jiǎn)介
Managed Profile,簡(jiǎn)稱被管理者賬戶。這個(gè)概念并不是什么新東西,因?yàn)樵缭?.2版本中,Android就引入了多用戶機(jī)制來(lái)解決平板使用上的問(wèn)題。而如今5.0新加入的這個(gè)被管理者賬戶功能,可以理解成為是為了解決用戶本人對(duì)于應(yīng)用進(jìn)行分類(lèi)的需求問(wèn)題而做的細(xì)化吧。
?
存在于被管理者賬戶中的應(yīng)用受制于主賬戶,也就是仍然處于機(jī)主本人的控制之下。但這些應(yīng)用的存儲(chǔ)空間,以及應(yīng)用的userID和PID都不同于主賬戶的同名應(yīng)用。
?
這些在被管理者賬戶中的應(yīng)用可以由機(jī)主進(jìn)行各方面的限制,比如說(shuō)控制這些應(yīng)用不能訪問(wèn)攝像頭——所有涉及到拍照部分的功能都開(kāi)啟不了,再比如說(shuō)控制某些特定應(yīng)用的功能——比如說(shuō)讓chrome的歷史記錄功能禁止使用。而所有的這些應(yīng)用都與主賬戶中的應(yīng)用隔離,這就意味著原本可能會(huì)被無(wú)故喚起的某些應(yīng)用放到這里之后,它也再也不會(huì)被另一些流氓應(yīng)用給后臺(tái)喚醒了。
?
前提條件
首先,你需要一臺(tái)安裝Android5.0及以上版本的手機(jī),親兒子系列最好,因?yàn)椴恢赖谌絉OM是否會(huì)將“加密”功能給閹割了。
開(kāi)啟手機(jī)加密的方法為:
設(shè)置——安全——加密手機(jī)
?
一般來(lái)說(shuō),手機(jī)出廠設(shè)置是不默認(rèn)加密的,需要用戶自己?jiǎn)?dòng)才行。當(dāng)然,也可以通過(guò)代碼來(lái)啟動(dòng)該功能,具體如下:
private voidregisterPovisionManagerProfile() { if (null== this) { return; } Intentintent = new Intent(ACTION_PROVISION_MANAGED_PROFILE); intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, this.getApplicationContext().getPackageName()); if(intent.resolveActivity(this.getPackageManager()) != null) { startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE); this.finish(); } else { Toast.makeText(this, "Device provisioning is not enabled.Stopping.", Toast.LENGTH_SHORT).show(); } } @Override public voidonActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == REQUEST_PROVISION_MANAGED_PROFILE) { if(resultCode == Activity.RESULT_OK) { Toast.makeText(getApplicationContext(), "Provisioning done.",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(getApplicationContext(), "Provisioningfailed.", Toast.LENGTH_SHORT).show(); } return; } super.onActivityResult(requestCode, resultCode, data); }之后根據(jù)引導(dǎo)窗口則可以完成加密手機(jī)并設(shè)置Managed Profile的流程。
具體模塊設(shè)計(jì)相關(guān)
對(duì)手機(jī)加密完成,并生成Managed Profile賬戶之后,我考慮了以下幾個(gè)問(wèn)題。
1.??????啟動(dòng)MP賬戶的流程
在google給出的官方樣例中,啟動(dòng)一個(gè)ManagedProfile已經(jīng)有了一套成熟的方案。
具體如下:
a)????????判斷當(dāng)前應(yīng)用是否已經(jīng)注冊(cè)為當(dāng)前賬戶的賬戶所有者(profile owner)——可以理解是擁有某些高級(jí)權(quán)限,類(lèi)似admin用戶。
b)????????如果不是,則參考加密的流程,發(fā)一個(gè)系統(tǒng)的intent啟動(dòng)加密流程。
c)????????如果是,那么恭喜你,你已經(jīng)處于一個(gè)MP中,并且擁有這個(gè)MP下的類(lèi)管理者權(quán)限了。
?
參考google的官方樣例BasicManagedProfile即可。
為了方便后續(xù)描述,當(dāng)前應(yīng)用我簡(jiǎn)稱為AdminApp好了。
?
2.??????如何添加現(xiàn)有應(yīng)用至MP賬戶中。
一般來(lái)說(shuō),查詢當(dāng)前系統(tǒng)中安裝的應(yīng)用狀態(tài)Android已經(jīng)有了非常方便的方式,通過(guò)PackageManager可以查到系統(tǒng)中安裝的各個(gè)包的信息總合,也可以指定特定的包名來(lái)查詢對(duì)應(yīng)信息。
但是,這個(gè)在MP賬戶中是做不到的。
?
比如常見(jiàn)的getInstalledPackages(intflag)方法,雖然平時(shí)調(diào)用時(shí)僅使用參數(shù)flags。但從源碼來(lái)看,真實(shí)的被調(diào)用者其實(shí)是被隱藏的方法getInstalledPackages(int flags,int userId),暴露給我們的方法中,userId已經(jīng)固定為當(dāng)前的用戶ID。
再看一下PackageManager服務(wù)進(jìn)程就能知道,真正在查詢安裝包信息時(shí),該方法需要將userID作為校驗(yàn)條件之一。通常一個(gè)Profile下對(duì)應(yīng)的所有應(yīng)用都有一個(gè)相同的userID,所以跨了Profile后就無(wú)法查詢主賬戶下的應(yīng)用信息了。
所以在默認(rèn)的MP賬戶中操作getInstalledPackages(),如果指明返回非系統(tǒng)應(yīng)用,則只會(huì)返回當(dāng)前應(yīng)用本身,其他的三方應(yīng)用是無(wú)法找到的。同樣,查找系統(tǒng)應(yīng)用也只能查找到在MP賬戶中注冊(cè)的系統(tǒng)應(yīng)用,沒(méi)有注冊(cè)的同樣也找不到。
?
因此,如果要添加相關(guān)應(yīng)用至MP賬戶中,無(wú)法通過(guò)輪詢當(dāng)前被管理者賬戶下所有的應(yīng)用名稱來(lái)一一添加。目前可行的有兩種方法,一種是用包名字串來(lái)激活,另一種是從主賬戶AP來(lái)獲取包名激活。
?
其中,谷歌的官方demo BasicManagedProfile使用的第一種方法,這里先進(jìn)行介紹這種方法。如何從主賬戶來(lái)獲取留在后面介紹。
?
還是以Chrome應(yīng)用為例。
Chrome的包名是:com.android.chrome
?
通過(guò)isApplicationEnabled方法可以判斷當(dāng)前這個(gè)應(yīng)用并沒(méi)有在MP賬戶中。具體的原理就是剛才所說(shuō)的userID隔離后的查詢的結(jié)果。
/** * Checks if the application is availablein this profile. * * @param packageName The package name * @return True if the application isavailable in this profile. */ private boolean isApplicationEnabled(String packageName) { … }Android對(duì)已知包名的系統(tǒng)應(yīng)用,提供了將其重新安裝到被管理者賬戶中的方法供AdminApp來(lái)調(diào)用。即public void enableSystemApp (ComponentName admin, StringpackageName)。
???????? 具體的使用流程可以參考demo中的代碼段:
/** * Enables or disables the specified app in this profile. * * @param packageName The package name of the target app. * @param enabled Pass true toenable the app. */ private voidsetAppEnabled(String packageName, boolean enabled) { }需要注明的一點(diǎn)是,這個(gè)方法只針對(duì)擁有INSTALL_PACKAGES權(quán)限的系統(tǒng)應(yīng)用有效,如果你傳入的第三方應(yīng)用包名,那么肯定會(huì)拋出IllegalArgumentException:Only system apps canbe enabled this way異常。
即使通過(guò)反射直接調(diào)用PackageManager服務(wù)的installExistingPackageAsUser(packageName,userID)方法,也會(huì)因?yàn)闄?quán)限的問(wèn)題而失敗。
?
所以,手動(dòng)添加第三方應(yīng)用到MP中目前我是沒(méi)有找到更好的方法,只能在建立MP之后重新安裝指定的第三方應(yīng)用,此時(shí),MP中會(huì)同樣安裝一份拷貝版本。
?
通過(guò)AdminApp調(diào)用enableSystemApp使能的系統(tǒng)應(yīng)用會(huì)出現(xiàn)在被管理者賬戶中,作為L(zhǎng)aunch的圖標(biāo)顯示出來(lái)。
:
同樣,如果不希望該應(yīng)用顯示在MP中,可以用AdminApp調(diào)用publicboolean setApplicationHidden (ComponentName admin, String packageName, booleanhidden)來(lái)隱藏。
簡(jiǎn)而言之,通過(guò)上述的操作,可以將一個(gè)系統(tǒng)應(yīng)用重新安裝到被管理者賬戶中。之后,你可以對(duì)這個(gè)被管理者賬戶中的應(yīng)用進(jìn)行限制操作了。
總結(jié)
以上是生活随笔為你收集整理的Android之Lollipop DevicePolicyManager学习(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: RC4加密解密java算法
- 下一篇: Android之Lollipop Dev