Android完全禁止第三方軟件安裝的方法

這段時間在給公司的產品做CTA認證,公司的產品聲明不允許第三方軟件安裝,所以需要禁止掉APK的安裝功能。一開始我把Packageinstaller.apk從系統裏面刪了,試了一下,放一個APK到SD卡,點擊安裝,確實安裝不了,我以爲就成功了,心想還挺簡單麼!!

不過,CTA認證實驗室說,不行,還是可以安裝第三方軟件!仔細問了一下,他們是通過PC端類似於“手機助手”的軟件安裝上去的。自己趕緊試了一下,確實可以安裝,又試了一下adb install命令,也可以安裝!!

得,還是問問軟件開發的同事吧,給個patch也行呀,誰知道人家太忙,沒時間搞,但是這事情分給我幹了,還是硬着頭皮搞吧。不過,對於一個搞驅動的,碰到這種應用的問題,半天都沒思路呀!!不過,功夫不負有心人,百度了一天,終於搞定了。

囉嗦完了,說正事!!

通過網上大神們對於Android系統APK安裝過程的分析,系統安裝APK主要的源碼在文件“frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java”裏,順便說一下,我用的是Android 5.0系統。

Android系統安裝APK有4種方式:
1. 開機時系統應用的安裝;
2. 手機APP下載應用安裝;
3. ADB命令安裝;
4. 點擊APK文件安裝;(我之前刪除的Packageinstaller.apk就是負責這種安裝)

第1種安裝方式函數調用結構大致如下:

PackageManagerService
->scanDirLI
–>scanPackageLI(File scanFile, …)
—>(省略)
—->mInstaller.install

剩下3種安裝方式,雖然開始是從不同接口進入,但是最後統一的調用如下:

installPackage
->scanPackageLI(PackageParser.Package pkg, …)
–>scanPackageDirtyLI
—>createDataDirsLI
—->mInstaller.install

由於不是很懂JAVA語法規則,所以,一開始我以爲,第1個“scanPackageLI”函數應該不會像下面的“scanPackageLI”函數一樣調用“createDataDirsLI”函數,所以我做如下修改“createDataDirsLI”函數:

    private int createDataDirsLI(String packageName, int uid, String seinfo) {
        int[] users = sUserManager.getUserIds();

        //直接返回失敗,禁止安裝APK
        return PackageManager.INSTALL_FAILED_INVALID_APK;

        /*
        int res = mInstaller.install(packageName, uid, uid, seinfo);
        if (res < 0) {
            return res;
        }
        for (int user : users) {
            if (user != 0) {
                res = mInstaller.createUserData(packageName,
                        UserHandle.getUid(user, uid), user, seinfo);
                if (res < 0) {
                    return res;
                }
            }
        }
        return res;
        */
    }

編譯運行之後發現,系統卡在開機動畫那裏不動了!!

所以,我估計第1種安裝方式的函數“scanPackageLI”一樣調用了“createDataDirsLI”函數,這個時候就麻煩了,系統APK的安裝和其他方式APK安裝調用一樣的函數!!

然後又去百度,看了大神的關於Android系統啓動時APK安裝過程的分析後,想到一個辦法,定義一個標誌位,用來標記系統啓動時APK是否安裝完成,當系統APK安裝沒有完成時,“createDataDirsLI”函數正常工作,當系統啓動完成,讓“createDataDirsLI”函數失效。

系統啓動時安裝APK調用的函數爲上面第1種安裝方式的“PackageManagerService”,然後調用“scanDirLI”函數完成安裝APK,安裝完成後,“調用updatePermissionsLPw來申請爲了特定的資源訪問權限的apk分配相應的linux用戶組ID”,這是文章原話。

所以先定義一個標誌位:private static boolean APK_install_finish = false;
初始化爲“false”代表系統APK安裝還沒有完成。

找到“PackageManagerService”函數內“updatePermissionsLPw”函數的調用處,發現只有一處。
在“updatePermissionsLPw”函數調用之前,“scanDirLI”函數調用之後,改變“APK_install_finish ”變量的值,表示系統APK安裝完成,代碼如下:

    ...

    Slog.i(TAG, "Time to scan packages: "
            + ((SystemClock.uptimeMillis()-startTime)/1000f)
            + " seconds");

    //系統APK安裝完成
    APK_install_finish = true;

    // If the platform SDK has changed since the last time we booted,
    // we need to re-grant app permission to catch any new ones that
    // appear.  This is really a hack, and means that apps can in some
    // cases get permissions that the user didn't initially explicitly
    // allow...  it would be nice to have some better way to handle
    // this situation.
    final boolean regrantPermissions = mSettings.mInternalSdkPlatform
            != mSdkVersion;
    if (regrantPermissions) Slog.i(TAG, "Platform changed from "
            + mSettings.mInternalSdkPlatform + " to " + mSdkVersion
            + "; regranting permissions for internal storage");
    mSettings.mInternalSdkPlatform = mSdkVersion;

    updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
            | (regrantPermissions
                    ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                    : 0));

    ...

然後重新修改“createDataDirsLI”函數:

    private int createDataDirsLI(String packageName, int uid, String seinfo) {
        int[] users = sUserManager.getUserIds();

        //如果系統APK安裝完成,則禁止安裝任何APK
        if(APK_install_finish)
        {
            return PackageManager.INSTALL_FAILED_INVALID_APK;
        }

        int res = mInstaller.install(packageName, uid, uid, seinfo);
        if (res < 0) {
            return res;
        }
        for (int user : users) {
            if (user != 0) {
                res = mInstaller.createUserData(packageName,
                        UserHandle.getUid(user, uid), user, seinfo);
                if (res < 0) {
                    return res;
                }
            }
        }
        return res;
    }

只有當系統APK安裝完成之後,才讓“createDataDirsLI”函數失效。

編譯下載運行,可以正常開機,開機之後,先使用ADB安裝APK,失敗;然後點擊APK裝包,安裝失敗;再使用PC端“手機助手”安裝APK,依然失敗!!

至此,大功告成~

相關參考文章鏈接:
http://blog.csdn.net/hdhd588/article/details/6739281
https://www.2cto.com/kf/201607/528367.html
http://blog.csdn.net/dkbdkbdkb/article/details/45313911

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章