参考文献:https://blog.csdn.net/xuezhe__/article/details/73130567

Android N(O) adb shell pm install package 流程分析

1、alps/android_mtk/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java

public static void main(String[] args) {
    int exitCode = 1;
    try {
        exitCode = new Pm().run(args);///////////step1
    } catch (Exception e) {
        Log.e(TAG, "Error", e);
        System.err.println("Error: " + e);
        if (e instanceof RemoteException) {
            System.err.println(PM_NOT_RUNNING_ERR);
        }
    }
    System.exit(exitCode);
}
public int run(String[] args) throws RemoteException {
    boolean validCommand = false;
    if (args.length < 1) {
        return showUsage();
    }
   ****************************************************
    if ("install".equals(op)) {
        return runInstall();/////////////////////step2
    }
private int runInstall() throws RemoteException {
    long startedTime = SystemClock.elapsedRealtime();
    final InstallParams params = makeInstallParams();
    final String inPath = nextArg();
    if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
        File file = new File(inPath);
        if (file.isFile()) {
            try {
                ApkLite baseApk = PackageParser.parseApkLite(file, 0); //////////step3
                PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
                        null, null); //////////////////////step4
                params.sessionParams.setSize(
                        PackageHelper.calculateInstalledSize(pkgLite, false,
                        params.sessionParams.abiOverride));
            } catch (PackageParserException | IOException e) {
                System.err.println("Error: Failed to parse APK file: " + e);
                return 1;
            }
        } else {
            System.err.println("Error: Can't open non-file: " + inPath);
            return 1;
        }
    }

    final int sessionId = doCreateSession(params.sessionParams,
            params.installerPackageName, params.userId);/////////////////////step5

    try {
        if (inPath == null && params.sessionParams.sizeBytes == -1) {
            System.err.println("Error: must either specify a package size or an APK file");
            return 1;
        }
        if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
                false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { ////////////step6
            return 1;
        }
        Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
        if (status.second != PackageInstaller.STATUS_SUCCESS) { //////////////////////step7
            return 1;
        }
        Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
                - startedTime) + " ms");
        System.out.println("Success");
        return 0;
    } finally {
        try {
            mInstaller.abandonSession(sessionId);
        } catch (Exception ignore) {
        }
    }
}
private int doCreateSession(SessionParams params, String installerPackageName, int userId)
        throws RemoteException {
    userId = translateUserId(userId, "runInstallCreate");
    if (userId == UserHandle.USER_ALL) {
        userId = UserHandle.USER_SYSTEM;
        params.installFlags |= PackageManager.INSTALL_ALL_USERS;
    }

    final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
    return sessionId;
}
private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)
        throws RemoteException {
    PackageInstaller.Session session = null;
    try {
        session = new PackageInstaller.Session(
                mInstaller.openSession(sessionId)); 

        final LocalIntentReceiver receiver = new LocalIntentReceiver();
        session.commit(receiver.getIntentSender());/////////////////step8

        final Intent result = receiver.getResult();
        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                PackageInstaller.STATUS_FAILURE);
        if (status == PackageInstaller.STATUS_SUCCESS) {
            if (logSuccess) {
                System.out.println("Success");
            }
        } else {
            System.err.println("Failure ["
                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
        }
        return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);
    } finally {
        IoUtils.closeQuietly(session);
    }
}

2、alps/frameworks/base/core/java/android/content/pm/PackageInstaller.java

public void commit(@NonNull IntentSender statusReceiver) {
    try {
        mSession.commit(statusReceiver, false);////////step9
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

3、alps/frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java

@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
    Preconditions.checkNotNull(statusReceiver);

   ***********************************
        mCommitted = true;
        mHandler.obtainMessage(MSG_COMMIT).sendToTarget(); ///////////////step10
    }

    if (!wasSealed) {
        // Persist the fact that we've sealed ourselves to prevent
        // mutations of any hard links we create. We do this without holding
        // the session lock, since otherwise it's a lock inversion.
        mCallback.onSessionSealedBlocking(this);
    }
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_COMMIT:
                synchronized (mLock) {
                    try {
                        commitLocked();////////////////step11
                    } catch (PackageManagerException e) {
                        final String completeMsg = ExceptionUtils.getCompleteMessage(e);
                        Slog.e(TAG,
                                "Commit of session " + sessionId + " failed: " + completeMsg);
                        destroyInternal();
                        dispatchSessionFinished(e.error, completeMsg, null);
                    }
                }

                break;
            case MSG_SESSION_FINISHED_WITH_EXCEPTION:
                PackageManagerException e = (PackageManagerException) msg.obj;

                dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e),
                        null);
                break;
        }

        return true;
    }
};
private void commitLocked()
        throws PackageManagerException {
     **************************************************
    mRelinquished = true;
    mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
            mInstallerPackageName, mInstallerUid, user, mCertificates);/////////////////step12 
}

4、alps/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

void installStage(String packageName, File stagedDir, String stagedCid,
        IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
        String installerPackageName, int installerUid, UserHandle user,
        Certificate[][] certificates) {
    **************************************************
    final Message msg = mHandler.obtainMessage(INIT_COPY);
    final int installReason = fixUpInstallReason(installerPackageName, installerUid,
            sessionParams.installReason);
    final InstallParams params = new InstallParams(origin, null, observer,
            sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
            verificationInfo, user, sessionParams.abiOverride,
            sessionParams.grantedRuntimePermissions, certificates, installReason);
    params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
    msg.obj = params;

    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
            System.identityHashCode(msg.obj));
    Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
            System.identityHashCode(msg.obj));

    mHandler.sendMessage(msg);//////////////////////step13 进入apk拷贝流程
}
void doHandleMessage(Message msg) {
    switch (msg.what) {
        case INIT_COPY: {
            HandlerParams params = (HandlerParams) msg.obj;
            int idx = mPendingInstalls.size();
            if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
            // If a bind was already initiated we dont really
            // need to do anything. The pending install
            // will be processed later on.
            if (!mBound) {
                Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                        System.identityHashCode(mHandler));
                // If this is the only one pending we might
                // have to bind to the service again.
                if (!connectToService()) {
                    Slog.e(TAG, "Failed to bind to media container service");
                    params.serviceError();
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                            System.identityHashCode(mHandler));
                    if (params.traceMethod != null) {
                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
                                params.traceCookie);
                    }
                    return;
                } else {
                    // Once we bind to the service, the first
                    // pending request will be processed.
                    mPendingInstalls.add(idx, params);
                }
            } else {
                mPendingInstalls.add(idx, params);
                // Already bound to the service. Just make
                // sure we trigger off processing the first request.
                if (idx == 0) {
                    mHandler.sendEmptyMessage(MCS_BOUND);/////////////////////step14
                }
            }
            break;
        }

case MCS_BOUND: {
    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
    if (msg.obj != null) {
        mContainerService = (IMediaContainerService) msg.obj;
        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
                System.identityHashCode(mHandler));
    }
    if (mContainerService == null) {
        if (!mBound) {
            // Something seriously wrong since we are not bound and we are not
            // waiting for connection. Bail out.
            Slog.e(TAG, "Cannot bind to media container service");
            for (HandlerParams params : mPendingInstalls) {
                // Indicate service bind error
                params.serviceError();
                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                        System.identityHashCode(params));
                if (params.traceMethod != null) {
                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
                            params.traceMethod, params.traceCookie);
                }
                return;
            }
            mPendingInstalls.clear();
        } else {
            Slog.w(TAG, "Waiting to connect to media container service");
        }
    } else if (mPendingInstalls.size() > 0) {
        HandlerParams params = mPendingInstalls.get(0);
        if (params != null) {
            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                    System.identityHashCode(params));
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
            if (params.startCopy()) { //////////////////////////////////////step15
                // We are done...  look for more work or to
                // go idle.
                if (DEBUG_SD_INSTALL) Log.i(TAG,
                        "Checking for more work or unbind...");
                // Delete pending install
                if (mPendingInstalls.size() > 0) {
                    mPendingInstalls.remove(0);
                }

final boolean startCopy() {
    boolean res;
    try {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

        if (++mRetries > MAX_RETRIES) {
            Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
            mHandler.sendEmptyMessage(MCS_GIVE_UP);
            handleServiceError();
            return false;
        } else {
            handleStartCopy();//////////////////////step16 开始apk的拷贝流程
            res = true;
        }
    } catch (RemoteException e) {
 ******************************************
}

......................

.......................

相关文章:

  • 2021-06-15
  • 2022-03-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-31
  • 2022-12-23
猜你喜欢
  • 2022-01-22
  • 2022-12-23
  • 2022-12-23
  • 2021-05-06
  • 2022-02-09
  • 2021-10-31
  • 2022-12-23
相关资源
相似解决方案