Android アプリケーション マーケットをクリックして APK をダウンロードするインストールの詳細

 Androidシステムの起動

1、「Android システムの起動プロセスの概要」

2、「Android init process起動処理」

3.「Android zygoteプロセス起動処理」

4.「Android SystemServerプロセス起動処理」

5.「Androidランチャー起動処理」

6.「Androidアクティビティ起動処理の詳細説明」

Androidシステム開発の準備

1、「Android ソースコードのダウンロードとコンパイル」

2.「Android 11のソースコードのコンパイルとpixel3のフラッシュ」

3.「Android フレームワーク コード IDE のロードとデバッグ」

Androidシステム開発実習

1.「Androidのデフォルト入力方法設定」

2、「Android フレームワークのプレハブ APK アプリケーション」

3.「Androidシステムレベルでのアプリ起動制限について詳しく解説」

4.「Android はフレームワーク モジュールを個別にコンパイルしてプッシュします」

5.「Androidフレームワーク開発システムの問題点分析」

Android システム開発のコアナレッジリザーブ記事

1、「Android コンパイル システム - envsetup とランチ コードの記事」

2.「Androidコンパイルシステム - コンセプト」

3.「Androidログシステムの詳しい解説」

4.「Androidシステムハンドラの詳細説明」

5.「Androidシステムバインダーの詳細説明」

6.「Androidのアクティビティ、ビュー、ウィンドウの関係を詳しく解説」

7.「Android View描画処理の詳細説明」

8.「Android リーディングシステム属性の詳細説明」

9.「Androidのウィンドウ管理の仕組みを詳しく解説」

10.「Androidシステムを初めて知る」

11.「Zygoteプロセスの新規プロセスフォークを通知するAndroidにおけるAMSプロセスの通信方法」

Androidのコア機能を詳しく解説

1.「Android アプリケーション マーケットをクリックして APK インストールの詳細をダウンロード」

2、「Android ジェスチャー ナビゲーション (下から上にスワイプしてマルチタスク ページに入る)」

3.「Android ジェスチャ分析 (アプリケーション インターフェイスを左から右にスワイプしてアプリケーションを終了します)」

4.「Androidアプリのインストール手順を詳しく解説」

5、「android11 インストールアプリケーションがデスクトップアイコンの更新プロセスをトリガーする」

6.「最近のAndroidシステムのマルチタスクについて詳しく解説」

7.「Android システム ナビゲーション バー ビューの分析」

———————————————————————————————————————————

目次

1. 背景の紹介

次に、インストールプロセス

2.1 プロセスの概要

2.2 パッケージインストーラーによる APK のインストール

2.3 PMS実行インストール


1. 背景の紹介

Android APK のインストール プロセスには、次の 4 つのインストール方法があります。

1. システム アプリケーションとプレハブ アプリケーションのインストールは、マシンの電源がオンになると完了します。インストール インターフェイスはなく、PKMS のコンストラクターでインストールが完了します。

2. ネットワークからアプリケーションをダウンロードしてインストールし、アプリケーション ストアを通じて完了し、PackageManager.installPackages() を呼び出します。インストール インターフェイスがあります。

3. ADB ツールはインストール インターフェイスなしでインストールされます。pm スクリプトが開始され、com.android.commands.pm.Pm クラスが呼び出され、PMS.installStage() が呼び出されてインストールが完了します。

4. SD カード内の APK ファイルを介してインストールされるサードパーティ アプリケーションのインストールにはインストール インターフェイスがあり、インストールおよびアンインストール プロセスのインターフェイスは packageinstaller.apk アプリケーションによって処理されます。

どちらも PackageInstallObserver を使用して、インストールが成功したかどうかを監視します。

次に、インストールプロセス

2.1 プロセスの概要

アプリケーションのインストールの主なプロセス:

1. APK 情報を IO ストリームの形式で PackageInstaller.Session に書き込みます。
2. PackageInstaller.Session の commit メソッドを呼び出し、APK 情報を処理のために PKMS に渡します。
3. APK
4をコピーし、最後にインストールします

        アプリケーション マーケットでアンインストールされた APK をクリックした後、ブロードキャストを送信して PackageInstallerActivity を開き、com.android.packageinstaller (ブレークポイント プロセス) アプリケーションをプルアップして、インストール インターフェイスをポップアップします。これは主に bindingUi で構成されています。 startInstall() を呼び出してインストールします。

/PackageInstallerActivity.java
private void bindUi() {
        mAlert.setIcon(mAppSnippet.icon);
        mAlert.setTitle(mAppSnippet.label);
        mAlert.setView(R.layout.install_content_view);
        mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
                (ignored, ignored2) -> {
                    if (mOk.isEnabled()) {
                        if (mSessionId != -1) {
                            mInstaller.setPermissionsResult(mSessionId, true);
                            finish();
                        } else {
                          //进行APK安装
                            startInstall();
                        }
                    }
                }, null);
        mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
                (ignored, ignored2) -> {
                    // Cancel and finish
                    setResult(RESULT_CANCELED);
                    if (mSessionId != -1) {
                      //如果mSessionId存在,执行setPermissionsResult()完成取消安装
                        mInstaller.setPermissionsResult(mSessionId, false);
                    }
                    finish();
                }, null);
        setupAlert();

       ......
    }

//点击”安装“,跳转 InstallInstalling - 开始安装
private void startInstall() {
    // Start subactivity to actually install the application
    Intent newIntent = new Intent();
    newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo);
    newIntent.setData(mPackageURI);
    newIntent.setClass(this, InstallInstalling.class);
    String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    ...
    if (installerPackageName != null) {
        newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
    }
    newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    startActivity(newIntent);
    finish();
}

このうち、R.layout.install_content_view レイアウト ビューは次のとおりです。

        インテントは startInstall メソッドで組み立てられ、アクティビティ InstallInstalling にジャンプし、現在の PackageInstallerActivity を閉じます。InstallInstalling では、主にパッケージ情報をパッケージ マネージャーに送信し、パッケージ管理コールバックを処理するために使用されます。

2.2 パッケージインストーラーによる APK のインストール

InstallInstalling を開始した後、onCreate メソッドを入力します。

//InstallInstalling
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ApplicationInfo appInfo = getIntent()
                .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = getIntent().getData();

          ......
            setupAlert();
            requireViewById(R.id.installing).setVisibility(View.VISIBLE);

            if (savedInstanceState != null) {
                mSessionId = savedInstanceState.getInt(SESSION_ID);
                mInstallId = savedInstanceState.getInt(INSTALL_ID);

                try {
                  //.根据mInstallId向InstallEventReceiver注册一个观察者,launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果savedInstanceState为null,代码的逻辑也是类似的
                    InstallEventReceiver.addObserver(this, mInstallId,
                            this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    // Does not happen
                }
            } else {
                ......

                File file = new File(mPackageURI.getPath());
                try {
                    PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                    params.setAppPackageName(pkg.packageName);
                    params.setInstallLocation(pkg.installLocation);
                    params.setSize(
                            PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
                } catch (PackageParser.PackageParserException e) {
                    Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                } catch (IOException e) {
                    Log.e(LOG_TAG,
                            "Cannot calculate installed size " + file + ". Try only apk size.");
                    params.setSize(file.length());
                }

                try {
                  //向InstallEventReceiver注册一个观察者返回一个新的mInstallId,
                  //其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回调给EventResultPersister。
                    mInstallId = InstallEventReceiver
                            .addObserver(this, EventResultPersister.GENERATE_NEW_ID,
                                    this::launchFinishBasedOnResult);
                } catch (EventResultPersister.OutOfIdsException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }

                try {
                  //PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId
                    mSessionId = getPackageManager().getPackageInstaller().createSession(params);
                } catch (IOException e) {
                    launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
                }
            }

            mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);

            mSessionCallback = new InstallSessionCallback();
        }
    }

        onCreate では、PackageInstaller を使用して Session を作成し、mSessionId を返します。その後、onResume で、InstallingAsynTask を開始し、mSessionId に対応するセッションにパッケージ情報を書き込み、送信します。

//InstallInstalling
protected void onResume() {
        super.onResume();

        // This is the first onResume in a single life of the activity
        if (mInstallingTask == null) {
            PackageInstaller installer = getPackageManager().getPackageInstaller();
          //获取sessionInfo
            PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);

            if (sessionInfo != null && !sessionInfo.isActive()) {
              //创建内部类InstallingAsyncTask的对象,调用execute(),最终进入onPostExecute()
                mInstallingTask = new InstallingAsyncTask();
                mInstallingTask.execute();
            } else {
                // we will receive a broadcast when the install is finished
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            }
        }
    }

  private final class InstallingAsyncTask extends AsyncTask<Void, Void,
            PackageInstaller.Session> {
              
    @Override
    protected PackageInstaller.Session doInBackground(Void... params) {
        
              PackageInstaller.Session session;
            try {
                session = getPackageManager().getPackageInstaller().openSession(mSessionId);
            } catch (IOException e) {
                return null;
            }

            session.setStagingProgress(0);

            try {
                File file = new File(mPackageURI.getPath());

                try (InputStream in = new FileInputStream(file)) {
                    long sizeBytes = file.length();
                  //从session中获取输出流
                    try (OutputStream out = session
                            .openWrite("PackageInstaller", 0, sizeBytes)) {
                        byte[] buffer = new byte[1024 * 1024];
                       ......
                    }
                }

                return session;
            } catch (IOException | SecurityException e) {
               ......
        }

        @Override
        protected void onPostExecute(PackageInstaller.Session session) {
            if (session != null) {
                Intent broadcastIntent = new Intent(BROADCAST_ACTION);
                broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                broadcastIntent.setPackage(getPackageName());
                broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);

                PendingIntent pendingIntent = PendingIntent.getBroadcast(
                        InstallInstalling.this,
                        mInstallId,
                        broadcastIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
                                //包写入session进行提交
                session.commit(pendingIntent.getIntentSender());
                mCancelButton.setEnabled(false);
                setFinishOnTouchOutside(false);
            } else {
                getPackageManager().getPackageInstaller().abandonSession(mSessionId);

                if (!isCancelled()) {
                    launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
                }
            }
        }  
   }

        InstallingAsyncTask の doInBackground() では、APK 情報がパッケージの Uri に従って IO ストリームの形式で PackageInstaller.Session に書き込まれ、最後に PackageInstaller.Session の commit メソッドが onPostExecute() で呼び出されてインストールされます。 。

        その中には、APK インストーラーである PackageInstaller が表示されます。これは、実際には ApplicationPackageManager の getPackageInstaller で作成されます。

//ApplicationPackageManager
@Override
    public PackageInstaller getPackageInstaller() {
        synchronized (mLock) {
            if (mInstaller == null) {
                try {
                    mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
                            mContext.getPackageName(), getUserId());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return mInstaller;
        }
    }

        ここでは、mPM.getPackageInstaller()、つまり IpacageInstaller のインスタンスが渡され、その具体的な実装は IPC を使用する PackageInstallerService です。初期化されると、/data/system ディレクトリにある install_sessions ファイルが読み取られ、このファイルにはシステムの未完了のインストール セッションが保存されます。PMS は、ファイルの内容に基づいて PackageInstallerSession オブジェクトを作成し、それを mSessions に挿入します。

//PackageInstallerService.java
 public PackageInstallerService(Context context, PackageManagerService pm,
            Supplier<PackageParser2> apexParserSupplier) {
        mContext = context;
        mPm = pm;
        mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);

        mInstallThread = new HandlerThread(TAG);
        mInstallThread.start();

        mInstallHandler = new Handler(mInstallThread.getLooper());

        mCallbacks = new Callbacks(mInstallThread.getLooper());

        mSessionsFile = new AtomicFile(
                new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
                "package-session");
   //这个文件保存了系统未完成的`Install Session`
        mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
        mSessionsDir.mkdirs();

        mApexManager = ApexManager.getInstance();
        mStagingManager = new StagingManager(this, context, apexParserSupplier);
    }

        Session をもう一度見てみましょう。これは、進行中のインストールを表す mSeesionId にバインドされたインストール セッションです。Session クラスは、IPackageInstaller.openSession(sessionId) によって取得された PackageInstallerSession (システム サーバー) のカプセル化です。

        セッションの作成と開始の具体的な実装は PackageInstallerService にあります。これは主に、apk のインストール情報と環境を初期化し、sessionId を作成し、インストール セッションを sessionId にバインドします。

        次に、InstallingAsyncTask に戻り、session.commit メソッドを呼び出します。

//PackageInstaller        
public void commit(@NonNull IntentSender statusReceiver) {
            try {
              //调用PackageInstallerSession的commit方法,进入到java框架层
                mSession.commit(statusReceiver, false);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

//PackageInstallerSession.java
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
                ......
          //如果尚未调用,则会话将被密封。此方法可能会被多次调用以更新状态接收者验证调用者权限
        if (!markAsSealed(statusReceiver, forTransfer)) {
            return;
        }
        //不同的包
        if (isMultiPackage()) {
            final SparseIntArray remainingSessions = mChildSessionIds.clone();
            final IntentSender childIntentSender =
                    new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
                            .getIntentSender();
            boolean sealFailed = false;
            for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
                final int childSessionId = mChildSessionIds.keyAt(i);
                // seal all children, regardless if any of them fail; we'll throw/return
                // as appropriate once all children have been processed
                if (!mSessionProvider.getSession(childSessionId)
                        .markAsSealed(childIntentSender, forTransfer)) {
                    sealFailed = true;
                }
            }
            if (sealFailed) {
                return;
            }
        }
        dispatchStreamValidateAndCommit();
}

private void dispatchStreamValidateAndCommit() {
        mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
    }
mSession のタイプは IPackageInstallerSession です。つまり、IPackageInstallerSession はプロセス間の通信に使用され、最後に PackageInstallerSession の commit メソッドが呼び出されます。
MSG_STREAM_VALIDATE_AND_COMMIT シグナルがここに送信され、ハンドラーで処理されます。
public boolean handleMessage(Message msg) {
        case MSG_STREAM_VALIDATE_AND_COMMIT:
           handleStreamValidateAndCommit();
           break;
            case MSG_INSTALL:
                handleInstall(); //
                break;
        ......
}

    private void handleStreamValidateAndCommit() {
        ......
            if (unrecoverableFailure != null) {
                onSessionVerificationFailure(unrecoverableFailure);
                // fail other child sessions that did not already fail
                for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
                    PackageInstallerSession session = nonFailingSessions.get(i);
                    session.onSessionVerificationFailure(unrecoverableFailure);
                }
            }
        }

        if (!allSessionsReady) {
            return;
        }

        mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
    }
handleStreamValidateAndCommit では、メッセージ MSG_INSTALL が再度送信されます。実際に実際に実行されるのは、handleInstall です。
private void handleInstall() {
        ......

        // 对于 multiPackage 会话,请在锁之外读取子会话,因为在持有锁的情况下读取子会话可能会导致死锁 (b123391593)。
        List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();

        try {
            synchronized (mLock) {
                installNonStagedLocked(childSessions);
            }
        } catch (PackageManagerException e) {
            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
            Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
            destroyInternal();
            dispatchSessionFinished(e.error, completeMsg, null);
        }
    }

private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
            throws PackageManagerException {
        ......
            if (!success) {
                sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
                        isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
                        failure.error, failure.getLocalizedMessage(), null);
                return;
            }
            mPm.installStage(installingChildSessions);
        } else {
            mPm.installStage(installingSession);
        }
    }

        最後に、PMS の installStage メソッドが実行されます。上記のプロセスでは、PackageInstaller を通じてセッションが維持され、インストール パッケージがセッションに書き込まれますが、実際のインストール プロセスは PMS を参照するところになります。

2.3 PMS実行インストール

//PackageManagerService.java
void installStage(List<ActiveInstallSession> children)
            throws PackageManagerException {
  //创建了类型未INIT_COPY的消息
        final Message msg = mHandler.obtainMessage(INIT_COPY);
  //创建InstallParams,它对应于包的安装数据
        final MultiPackageInstallParams params =
                new MultiPackageInstallParams(UserHandle.ALL, children);
        params.setTraceMethod("installStageMultiPackage")
                .setTraceCookie(System.identityHashCode(params));
        msg.obj = params;

        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStageMultiPackage",
                System.identityHashCode(msg.obj));
        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                System.identityHashCode(msg.obj));
  //将InstallParams通过消息发送出去
        mHandler.sendMessage(msg);
    }

ハンドラーは INIT_COPY のメッセージを処理します。

//PackageManagerService.java
void doHandleMessage(Message msg) {
            switch (msg.what) {
                case INIT_COPY: {
                    HandlerParams params = (HandlerParams) msg.obj;
                    if (params != null) {
                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                System.identityHashCode(params));
                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                      //执行APK拷贝动作
                        params.startCopy();
                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                    }
                    break;
                }
                ......
            }
  
  final void startCopy() {
            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
            handleStartCopy();
            handleReturnCode();
        }

        ここでは 2 つのメソッド handleStartCopy と handleReturnCode が呼び出され、それらの実装は InstallParams にあります。
handleStartCopy では、次の操作が実行されます。

  • スペースのサイズを確認し、十分なスペースがない場合は、無駄なスペースを解放します。
  • 元のインストール場所にファイルを上書きし、戻り結果に応じて関数の戻り値を決定し、installFlags を設定します
  • インストールされているパッケージ検証ツールがあるかどうかを確認し、存在する場合は検出を遅延します。主に3つのステップに分かれており、最初に検証インテントを作成し、次に関連情報を設定し、次にバリデータリストを取得し、最後に検証インテントを各バリデータに送信します
public void handleStartCopy() {
  ......
    //解析包 返回最小的细节:pkgName、versionCode、安装所需空间大小、获取安装位置等
    pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
                    origin.resolvedPath, installFlags, packageAbiOverride);
  ......
    //覆盖原有安装位置的文件,并根据返回结果来确定函数的返回值,并设置installFlags。
    if (ret == PackageManager.INSTALL_SUCCEEDED) {
                int loc = pkgLite.recommendedInstallLocation;
                if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
                    ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
                    ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                    ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
                } else {
                     .......
                }
            }
  
  //安装参数
  final InstallArgs args = createInstallArgs(this);
            mVerificationCompleted = true;
            mIntegrityVerificationCompleted = true;
            mEnableRollbackCompleted = true;
            mArgs = args;

            if (ret == PackageManager.INSTALL_SUCCEEDED) {
                final int verificationId = mPendingVerificationToken++;

                // apk完整性校验
                if (!origin.existing) {
                    PackageVerificationState verificationState =
                            new PackageVerificationState(this);
                    mPendingVerification.append(verificationId, verificationState);

                    sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
                    ret = sendPackageVerificationRequest(
                            verificationId, pkgLite, verificationState);

                    ......
                }

}

次に、handleReturnCode メソッドを確認します。

@Override
        void handleReturnCode() {
            ......
                if (mRet == PackageManager.INSTALL_SUCCEEDED) {
                  //执行APKcopy拷贝
                    mRet = mArgs.copyApk();
                }
          //执行安装
                processPendingInstall(mArgs, mRet);
            }
        }

APKのコピープロセスはどのようにコピーされますか:

//packageManagerService.java
int copyApk() {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
            try {
                return doCopyApk();
            } finally {
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
        }

private int doCopyApk() {
            ......

            int ret = PackageManagerServiceUtils.copyPackage(
                    origin.file.getAbsolutePath(), codeFile);
            ......
            return ret;
        }
//继续追踪下去,他会到PackagemanagerSeriveUtils的copyFile方法

//PackagemanagerSeriveUtils
private static void copyFile(String sourcePath, File targetDir, String targetName)
            throws ErrnoException, IOException {
        if (!FileUtils.isValidExtFilename(targetName)) {
            throw new IllegalArgumentException("Invalid filename: " + targetName);
        }
        Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);

        final File targetFile = new File(targetDir, targetName);
        final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
                O_RDWR | O_CREAT, 0644);
        Os.chmod(targetFile.getAbsolutePath(), 0644);
        FileInputStream source = null;
        try {
            source = new FileInputStream(sourcePath);
            FileUtils.copy(source.getFD(), targetFd);
        } finally {
            IoUtils.closeQuietly(source);
        }
    }

        ここでは、ファイル ストリームの操作を通じて APK が /data/app ディレクトリにコピーされます。コピーが完了したら、実際のインストールに入ります。プロセスは次のとおりです。

/PackageManagerService.java
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
        if (args.mMultiPackageInstallParams != null) {
            args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
        } else {
          //安装结果
            PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
          //创建一个新线程来处理安转参数来进行安装
            processInstallRequestsAsync(
                    res.returnCode == PackageManager.INSTALL_SUCCEEDED,
                    Collections.singletonList(new InstallRequest(args, res)));
        }
    }

//排队执行异步操作
private void processInstallRequestsAsync(boolean success,
            List<InstallRequest> installRequests) {
        mHandler.post(() -> {
            if (success) {
                for (InstallRequest request : installRequests) {
                  //进行检验,如果之前安装失败,则清除无用信息
                    request.args.doPreInstall(request.installResult.returnCode);
                }
                synchronized (mInstallLock) {
                  //安装的核心方法,进行解析apk安装
                    installPackagesTracedLI(installRequests);
                }
                for (InstallRequest request : installRequests) {
                  //再次检验清除无用信息
                  
                    request.args.doPostInstall(
                            request.installResult.returnCode, request.installResult.uid);
                }
            }
            for (InstallRequest request : installRequests) {
              //备份、可能的回滚、发送安装完成先关广播
                restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
                        new PostInstallData(request.args, request.installResult, null));
            }
        });
    }

コア メソッド installPackagesTracedLI を確認し、内部で installPackagesLI メソッドを実行しました。

//PackageMmanagerSerice.java 
private void installPackagesLI(List<InstallRequest> requests) {
   .......
     //分析当前任何状态,分析包并对其进行初始化验证
     prepareResult =
          preparePackageLI(request.args, request.installResult);
      
  ......
    //根据准备阶段解析包的信息上下文,进一步解析
      final ScanResult result = scanPackageTracedLI(
                            prepareResult.packageToScan, prepareResult.parseFlags,
                            prepareResult.scanFlags, System.currentTimeMillis(),
                            request.args.user, request.args.abiOverride);     
    .......
      //验证扫描后包的信息好状态,确保安装成功
      reconciledPackages = reconcilePackagesLocked(
                            reconcileRequest, mSettings.mKeySetManagerService);
          
        //提交所有的包并更新系统状态。这是安装流中唯一可以修改系统状态的地方,必须在此阶段之前确定所有可预测的错误
        commitRequest = new CommitRequest(reconciledPackages,
                            mUserManager.getUserIds());
                    commitPackagesLocked(commitRequest);
  .......
    //完成APK安装
  executePostCommitSteps(commitRequest);
 }

上記のコードからわかるように、installPackagesLI は主に次のことを行います。

  • 現在の状態を分析し、パッケージを分析して初期化検証を実行します。
  • 準備フェーズの解析パッケージの情報コンテキストに従って、さらに解析
  • インストールが成功したことを確認するために、スキャン後にパッケージ情報のステータスを確認します。
  • すべての Sao Oh Omiao パッケージを送信し、システム ステータスを更新します
  • APKのインストールを完了する

preparePackageLI() で PackageParser2.parsePackage() を使用して AndroidManifest.xml を解析し、4 つの主要コンポーネントなどの情報を取得します。ParsingPackageUtils.getSigningDetails() を使用して署名情報を解析し、パッケージの最終パスの名前を変更します。

解析と検証の準備が完了したら、最後のステップは apk をインストールすることです。ここでは、executePostCommitSteps が呼び出され、アプリデータを準備し、DEX 最適化を実行します。

//PackageManagerService.java
private void executePostCommitSteps(CommitRequest commitRequest) {
  //进行安装
  prepareAppDataAfterInstallLIF(pkg);
   .......
   final boolean performDexopt =
                    (!instantApp || Global.getInt(mContext.getContentResolver(),
                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                    && !pkg.isDebuggable()
                    && (!onIncremental);
  
  //为新的代码路径准备应用程序配置文件
  mArtManagerService.prepareAppProfiles(
                    pkg,
                    resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
  
  if (performDexopt) {

             ......
               //其中分配了 dexopt 所需的库文件
               PackageSetting realPkgSetting = result.existingSettingCopied
                        ? result.request.pkgSetting : result.pkgSetting;
                if (realPkgSetting == null) {
                    realPkgSetting = reconciledPkg.pkgSetting;
                }
                
                            //执行dex优化
                mPackageDexOptimizer.performDexOpt(pkg, realPkgSetting,
                        null /* instructionSets */,
                        getOrCreateCompilerPackageStats(pkg),
                        mDexManager.getPackageUseInfoOrDefault(packageName),
                        dexoptOptions);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
            }
}

prepareAppDataAfterInstallLIF メソッドでは、一連の呼び出しの後、最後に mInstaller.createAppData が呼び出されます。これは、Installd デーモン プロセスを呼び出すためのエントリ ポイントでもあります。

public class Installer extends SystemService {
    
   @Override
    public void onStart() {
        if (mIsolated) {
            mInstalld = null;
        } else {
          //通过Binder调用到进程installd
            connect();
        }
    }

    private void connect() {
        IBinder binder = ServiceManager.getService("installd");
        ......

        if (binder != null) {
            mInstalld = IInstalld.Stub.asInterface(binder);
            try {
                invalidateMounts();
            } catch (InstallerException ignored) {
            }
        } else {
            Slog.w(TAG, "installd not found; trying again");
            BackgroundThread.getHandler().postDelayed(() -> {
                connect();
            }, DateUtils.SECOND_IN_MILLIS);
        }
    }
  
     public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
            String seInfo, int targetSdkVersion) throws InstallerException {
        if (!checkBeforeRemote()) return -1;
        try {
          //进行安装操作
            return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
                    targetSdkVersion);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
    }
    }

最後に、Installd の createAppData メソッドがインストールのために呼び出されていることがわかります。インストーラは Java 層によって提供される Java API インターフェイスであり、Installd は init プロセスで起動される root 権限を持つデーモン プロセスです。

processInstallRequestsAsync の最後のステップで、restoreAndPostInstall が呼び出され、インストールが完了すると POST_INSTALL メッセージが送信されます。

//PackageManagerService.java
private void restoreAndPostInstall(
            int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
  
  .......
    if (!doRestore) {
            
            if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);

            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);

            Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
            mHandler.sendMessage(msg);
        }
}

void doHandleMessage(Message msg) {
  .......
  case POST_INSTALL: {
    .......
      //处理安装结果
    handlePackagePostInstall(parentRes, grantPermissions,
                                killApp, virtualPreload, grantedPermissions,
                                whitelistedRestrictedPermissions, autoRevokePermissionsMode,
                                didRestore, args.installSource.installerPackageName, args.observer,
                                args.mDataLoaderType);
  }
}

private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
            boolean killApp, boolean virtualPreload,
            String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
            int autoRevokePermissionsMode,
            boolean launchedForRestore, String installerPackage,
            IPackageInstallObserver2 installObserver, int dataLoaderType) {
  
  ......
    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                        extras, 0 /*flags*/,
                        null /*targetPackage*/, null /*finishedReceiver*/,
                        updateUserIds, instantUserIds, newBroadcastWhitelist);
}

最後に、ACTION_PACKAGE_ADDED ブロードキャストが送信され、ランチャーはこのブロードキャストを受信した後、デスクトップにアプリケーション アイコンを追加します。

おすすめ

転載: blog.csdn.net/allen_xu_2012_new/article/details/130770012