android多用戶下應用安裝詳解三(特殊需求實現)

     前兩篇已經對新應用安裝和開機加載應用安裝信息的流程做了詳細梳理,下面來看一個需求。在說這個需求之前,我們瞭解一個背景:多用戶下,如果使用adb install xxx.apk的話,會導致全用戶安裝。聰明的讀者可能就知道了,這實際上破壞了多用戶的獨立性。而我所在的項目即利用到了多用戶,這顯然不能讓人接受,尤其是很多pc上的android應用安裝工具,會直接把一些應用安裝到另外一個用戶裏。實際上這也是我調研這個問題的原因。

   下面來分析全用戶安裝的原因:

  1.  packagemanagerservice安裝入口installPackageWithVerificationAndEncryption()裏:

           UserHandle user;
        if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
            user = UserHandle.ALL;          
        } else {
            user = new UserHandle(UserHandle.getUserId(uid));
        }

       看到這裏,可以大致猜測就是這個UserHandle.ALL導致的全用戶安裝的,實際的情況也確實是這樣的,在層層傳遞之後,會進入com.android.server.pm.Settings.getPackageLPw(): 有一段邏輯是這樣的:

              List<UserInfo> users = getAllUsers();
                    if (users != null && allowInstall) {
                        for (UserInfo user : users) {
                            final boolean installed = installUser == null
                                    || installUser.getIdentifier() == UserHandle.USER_ALL
                                    || installUser.getIdentifier() == user.id;
                            p.setUserState(user.id, COMPONENT_ENABLED_STATE_DEFAULT,
                                    installed,
                                    true, // stopped,
                                    true, // notLaunched
                                    false, // blocked
                                    null, null, null);
                            writePackageRestrictionsLPr(user.id);
                        }
                    }

         看到這裏肯定就明白了,所以一個直觀的想法就是修改這段邏輯

             if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
                      user = UserHandle.ALL;          
               }

          改爲:user = new UserHandle(ActivityManagerNative.getDefault().getCurrentUser().id);    即如果使用adb install的話就將安裝用戶設爲當前前臺用戶,避免全用戶安裝。


2.  這個確實能屏蔽絕大部分情況,但是還是屏蔽不了所有的情況:

      比如adb push xxx.apk /data/app,  當然這個需要系統權限,三方安裝工具是沒有這個權限的。

  但還有一種情況,卻是真的可能發生。就是安裝過程中手機重啓,尤其是一些國產手機比較容易出現,這樣的情況就會如上篇中所講,開機掃描到/data/app目錄下有新apk的時候就會重新走安裝流程。

 

  private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
       
        for (i=0; i<files.length; i++) {
            ................................................................................................................
            PackageParser.Package pkg = scanPackageLI(file,

                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);

            這裏面最後一個參數就是installUser, 如果等於null, 根據第一篇第7部分知道也會被全用戶安裝

            ................................................................................................................          
        }
    }

3.  所以我們如果想徹底屏蔽全用戶安裝,需要找到一個所有情況都會走到的地方。

    實際這個地方就是com.android.server.pm.Settings.getPackageLPw(String name, PackageSetting origPackage,
            String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
            String nativeLibraryPathString, int vc, int pkgFlags,
            UserHandle installUser, boolean add, boolean allowInstall)方法,因爲第一篇,第二篇的分析知道,不管是正常的安裝流程,還是開機掃描/data/app目錄,包括開機之後監聽/data/app目錄都會最終走到這個方法裏。所以我們只需要在這個方法裏將installUser設爲當前用戶即可。

 即:  installUser = new UserHandle(ActivityManagerNative.getDefault().getCurrentUser().id);


ok.這就是延伸出來的一個需求修改。網上關於多用戶分析的技術文章還比較少,有用的更是不可得,所以這裏對自己的分析做一個記錄分享。


發佈了37 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章