android PKMS-1 installStart文件詳解

1 概述

installStart 本質(zhì)一個Activity策幼,屬于系統(tǒng)應(yīng)用程序PackageInstaller

android8.0后系統(tǒng)禁止跨進(jìn)程傳遞文件url巡通,所以文件的url都以content做scheme來進(jìn)行傳遞
8.0后安裝應(yīng)用請求

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(xxxxx, "application/vnd.android.package-archive");

這里通過封裝該intent啟動InstallStartActivity

        <activity android:name=".InstallStart"
                android:theme="@android:style/Theme.Translucent.NoTitleBar"
                android:exported="true"
                android:excludeFromRecents="true">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="content" />
                <data android:mimeType="application/vnd.android.package-archive" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.INSTALL_PACKAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="package" />
                <data android:scheme="content" />
            </intent-filter>
            <intent-filter android:priority="1">
                <action android:name="android.content.pm.action.CONFIRM_INSTALL" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

通過PackageInstaller應(yīng)用程序的manifest.xml文件我們可以知道為什么會啟動InstallStart

 <intent-filter android:priority="1">
                <action android:name="android.intent.action.VIEW" />
                <data android:scheme="content" />
                <data android:mimeType="application/vnd.android.package-archive" />
 </intent-filter>

2 installStart都做了什么

首先作為Activity内边,在啟動后一定遵循生命周期

2.1 onCreate
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //獲取packageManager
        mPackageManager = getPackageManager();
        //獲取UserManager類對象
        mUserManager = getSystemService(UserManager.class);
        //獲取調(diào)用方intent
        Intent intent = getIntent();
        // 獲取調(diào)用者包名用于驗(yàn)證調(diào)用者信息
        String callingPackage = getCallingPackage();
        String callingAttributionTag = null;
        //這里ACTION_CONFIRM_INSTALL主要是用戶確認(rèn)是否安裝應(yīng)用的操作
        //一般場景為安裝程序需要執(zhí)行敏感操作,需用戶確認(rèn)才能繼續(xù)安裝
        final boolean isSessionInstall =
                PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());

        // If the activity was started via a PackageInstaller session, we retrieve the calling
        // package from that session
        //這里獲取安裝sessionid,普通安裝 sessionid -1
        final int sessionId = (isSessionInstall
                ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
                : -1);
        
        /**
         * 這里主要針對這種異常case進(jìn)行判斷
         * 調(diào)用者包信息闰渔,找不到暮现,但是存在安裝會話
         */
        if (callingPackage == null && sessionId != -1) {
            PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
            PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
            callingPackage = (sessionInfo != null) ? sessionInfo.getInstallerPackageName() : null;
            callingAttributionTag =
                    (sessionInfo != null) ? sessionInfo.getInstallerAttributionTag() : null;
        }
        //根據(jù)包獲取應(yīng)用相關(guān)信息
        final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
        //獲取元進(jìn)程用戶id
        final int originatingUid = getOriginatingUid(sourceInfo);
        //定義了一個flag还绘,作用 檢查安裝資源是否值得信任
        boolean isTrustedSource = false;
        if (sourceInfo != null
                && (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
            /**
             * case
             * 條件 元進(jìn)程不為空,并且元進(jìn)程為系統(tǒng)應(yīng)用進(jìn)程
             * 
             * 從intent獲取EXTRA_NOT_UNKNOWN_SOURCE的值確認(rèn)是否為值得信任的資源
             */
            isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
        }

        if (!isTrustedSource && originatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
            /**
             * case 如果不是可信任資源且元進(jìn)程的uid不是未知的
             * 
             * 過程
             * 獲取sdk版本
             * 獲取失敗直接拒絕安裝
             * 
             * 獲取成功
             * 檢查sdk版本大于 Build.VERSION_CODES.O并且該UID所對應(yīng)應(yīng)用未請求安裝包權(quán)限
             * 
             *拒絕安裝
             */
            final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
            if (targetSdkVersion < 0) {
                Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
                // Invalid originating uid supplied. Abort install.
                mAbortInstall = true;
            } else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission(
                    originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
                Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
                        + Manifest.permission.REQUEST_INSTALL_PACKAGES);
                mAbortInstall = true;
            }
        }
        if (mAbortInstall) {
            //設(shè)置啟動結(jié)果RESULT_CANCELED 通知啟動activity
            setResult(RESULT_CANCELED);
            //關(guān)閉當(dāng)前activity
            finish();
            return;
        }
        //這里構(gòu)建新的intent封裝 啟動Activity的intent
        Intent nextActivity = new Intent(intent);
        //定義新intent的flag
        //Intent.FLAG_ACTIVITY_FORWARD_RESULT 通知啟動Activity可以接受結(jié)果
        // Intent.FLAG_GRANT_READ_URI_PERMISSION 設(shè)置目標(biāo)activity可以讀取url
        nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                | Intent.FLAG_GRANT_READ_URI_PERMISSION);

        // The the installation source as the nextActivity thinks this activity is the source, hence
        // set the originating UID and sourceInfo explicitly
        //元進(jìn)程包信息
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_ATTRIBUTION_TAG,
                callingAttributionTag);
        //元進(jìn)程 進(jìn)程信息
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
        //元進(jìn)程 用戶id
        nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);

        if (isSessionInstall) {
            /**
             * case1 這里判斷當(dāng)前是否為用戶確認(rèn)安裝操作
             * 
             * 結(jié)果 跳轉(zhuǎn)到PackageInstallerActivity
             * 
             */
            nextActivity.setClass(this, PackageInstallerActivity.class);
        } else {
            /**
             * case2 普通安裝栖袋,這里檢查packageUri的Scheme是否為content
             * 
             * 結(jié)果跳轉(zhuǎn)到InstallStaging
             */
            Uri packageUri = intent.getData();
            if (packageUri != null && packageUri.getScheme().equals(
                    ContentResolver.SCHEME_CONTENT)) {
                // [IMPORTANT] This path is deprecated, but should still work. Only necessary
                // features should be added.

                // Copy file to prevent it from being changed underneath this process
                nextActivity.setClass(this, InstallStaging.class);
            } else if (packageUri != null && packageUri.getScheme().equals(
                    PackageInstallerActivity.SCHEME_PACKAGE)) {
                //case3 這里判斷packageUri的scheme是否為package
                nextActivity.setClass(this, PackageInstallerActivity.class);
            } else {
                //case4 如果上述幾種情況都不滿足拍顷,則通知源端,應(yīng)用安裝失敗
                Intent result = new Intent();
                result.putExtra(Intent.EXTRA_INSTALL_RESULT,
                        PackageManager.INSTALL_FAILED_INVALID_URI);
                setResult(RESULT_FIRST_USER, result);

                nextActivity = null;
            }
        }

        if (nextActivity != null) {
            //啟動下一個Activity
            startActivity(nextActivity);
        }
        //退出當(dāng)前activity
        finish();
    }

總結(jié):InstallStart類作為系統(tǒng)應(yīng)用程序安裝啟動的第一個Activity塘幅,它的主要職責(zé)為

  • 1 獲取元進(jìn)程的包信息昔案,應(yīng)用信息 用戶id
  • 2 確認(rèn)當(dāng)次操作是普通安裝還是用戶確認(rèn)安裝
  • 3 確認(rèn)安裝資源是否可信任
  • 4 最后根據(jù)安裝方式和intent的data的scheme來確認(rèn)跳轉(zhuǎn)哪一個Acitivty,進(jìn)行接下來的處理

普通安裝這里首先看InstallStaging

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末电媳,一起剝皮案震驚了整個濱河市踏揣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匾乓,老刑警劉巖捞稿,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拼缝,居然都是意外死亡娱局,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門咧七,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衰齐,“玉大人,你說我怎么就攤上這事继阻〗空叮” “怎么了仁卷?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長犬第。 經(jīng)常有香客問我锦积,道長,這世上最難降的妖魔是什么歉嗓? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任丰介,我火速辦了婚禮,結(jié)果婚禮上鉴分,老公的妹妹穿的比我還像新娘哮幢。我一直安慰自己,他們只是感情好志珍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布橙垢。 她就那樣靜靜地躺著,像睡著了一般伦糯。 火紅的嫁衣襯著肌膚如雪柜某。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天敛纲,我揣著相機(jī)與錄音喂击,去河邊找鬼。 笑死淤翔,一個胖子當(dāng)著我的面吹牛翰绊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旁壮,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼监嗜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抡谐?” 一聲冷哼從身側(cè)響起秤茅,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎童叠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體课幕,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厦坛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了乍惊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杜秸。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖润绎,靈堂內(nèi)的尸體忽然破棺而出撬碟,到底是詐尸還是另有隱情诞挨,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布呢蛤,位于F島的核電站惶傻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏其障。R本人自食惡果不足惜银室,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望励翼。 院中可真熱鬧蜈敢,春花似錦、人聲如沸汽抚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽造烁。三九已至否过,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間膨蛮,已是汗流浹背叠纹。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敞葛,地道東北人誉察。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像惹谐,于是被迫代替她去往敵國和親持偏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容