Android應用安裝原理--Android是如何認定應用爲未知來源

啓動應用安裝的第一步是啓動PackageInstallerActivity,在PackageInstallerActivity會進行應用來源認證:

    private boolean isInstallRequestFromUnknownSource(Intent intent) {
        String callerPackage = getCallingPackage();
        if (callerPackage != null && intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
            try {
                mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
                if (mSourceInfo != null) {
                    if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
                        // Privileged apps are not considered an unknown source.
                        return false;
                    }
                }
            } catch (NameNotFoundException e) {
            }
        }


        return true;
    }
下面來分條梳理認證的條件:

  1. callerPackage = getCallingPackage();
    callerPackage != null
    
    

    public String getCallingPackage ()

    Added in API level 1

    Returnthe name of the package that invoked this activity. This is who the data in setResult() will be sent to. You can use this information to validate that the recipient is allowed to receive the data.

    Note:if the calling activity is not expecting a result (that is it did not use the startActivityForResult(Intent, int) form that includes a request code),then the callingpackage will be null.

    Note:prior to JELLY_BEAN_MR2, the result from this method was unstable. If the process hosting the calling package was no longer running, it would return null instead of the proper package name. You can use getCallingActivity() and retrieve the package namefrom that instead.

    Returns

    ·         The package of  the activity that will receive your reply, or null if none.

    從API文檔介紹裏可以知道:需要在拉起PackageInstallerActivity 的時候使用startActivityForResult(Intent, int) 才能在PackageInstallerActivity中通過 getCallingPackage () 獲取到 packageName,否則爲null,即認定應用來源爲未知。                                                                                                                                               根據我的經驗,拉起PackageInstallerActivity的Intent若是設置了下面的FLAG,也會導致getCallingPackage () 獲取到 packageName爲null(參考:startActivityForResult中的說明):
    Intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    具體原因需要分析getCallingPackage(),這個坑以後再填吧   //TO DO 分析getCallingPackage()
  2.    
    intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false) == true

這個只需在拉起PackageInstallerActivity的Intent附上Intent.EXTRA_NOT_UNKNOWN_SOURCE ,值爲true 就行

3. mSourceInfo 只要callerPackage 不爲null,就不會爲null;

4. mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED

ApplicationInfo.FLAG_PRIVILEGED 表示該應用是 Privileged App, 即啓動PackageInstallerActivity的應用是安裝在system/priv-app/ 下的

下面是一個例子:整個測試程序只有下面一個java文件,

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent i = new Intent(Intent.ACTION_INSTALL_PACKAGE);
        String filePath = "/storage/emulated/0/test.apk";
        Uri uri = Uri.parse("file://" + filePath);
        i.setData(uri);
        i.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
        i.putExtra(Intent.EXTRA_RETURN_RESULT, true);
        i.setClassName("com.android.packageinstaller",
                "com.android.packageinstaller.PackageInstallerActivity");
        startActivityForResult(i, 10);

    }
}
將應用編譯出來後,把apk文件push到手機/system/app/下面(需要root權限),然後在/storage/emulated/0/下放一個用於安裝的軟件test.apk,就可以測試了。

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