Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a0386dd authored by Songchun Fan's avatar Songchun Fan Committed by Android (Google) Code Review
Browse files

Merge "[pm] extract InstallParams from PackageManagerService class"

parents 667755fd 296502a3
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.annotation.NonNull;

import java.util.Map;

/**
 * Package state to commit to memory and disk after reconciliation has completed.
 */
final class CommitRequest {
    final Map<String, ReconciledPackage> mReconciledPackages;
    @NonNull final int[] mAllUsers;

    CommitRequest(Map<String, ReconciledPackage> reconciledPackages,
            @NonNull int[] allUsers) {
        mReconciledPackages = reconciledPackages;
        mAllUsers = allUsers;
    }
}
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.os.UserHandle;

final class DeletePackageAction {
    public final PackageSetting mDeletingPs;
    public final PackageSetting mDisabledPs;
    public final PackageRemovedInfo mRemovedInfo;
    public final int mFlags;
    public final UserHandle mUser;

    DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
            PackageRemovedInfo removedInfo, int flags, UserHandle user) {
        mDeletingPs = deletingPs;
        mDisabledPs = disabledPs;
        mRemovedInfo = removedInfo;
        mFlags = flags;
        mUser = user;
    }
}
+263 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;

import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.makeDirRecursive;

import android.content.pm.DataLoaderType;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Environment;
import android.os.FileUtils;
import android.os.SELinux;
import android.os.Trace;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;

import com.android.internal.content.NativeLibraryHelper;
import com.android.server.pm.parsing.pkg.ParsedPackage;

import libcore.io.IoUtils;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * Logic to handle installation of new applications, including copying
 * and renaming logic.
 */
class FileInstallArgs extends InstallArgs {
    private File mCodeFile;

    // Example topology:
    // /data/app/com.example/base.apk
    // /data/app/com.example/split_foo.apk
    // /data/app/com.example/lib/arm/libfoo.so
    // /data/app/com.example/lib/arm64/libfoo.so
    // /data/app/com.example/dalvik/arm/base.apk@classes.dex

    /** New install */
    FileInstallArgs(InstallParams params) {
        super(params);
    }

    /** Existing install */
    FileInstallArgs(String codePath, String[] instructionSets, PackageManagerService pm) {
        super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
                null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                SigningDetails.UNKNOWN,
                PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
                false, DataLoaderType.NONE, pm);
        mCodeFile = (codePath != null) ? new File(codePath) : null;
    }

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

    private int doCopyApk() {
        if (mOriginInfo.mStaged) {
            if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
            mCodeFile = mOriginInfo.mFile;
            return PackageManager.INSTALL_SUCCEEDED;
        }

        try {
            final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
            final File tempDir =
                    mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
            mCodeFile = tempDir;
        } catch (IOException e) {
            Slog.w(TAG, "Failed to create copy file: " + e);
            return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
        }

        int ret = PackageManagerServiceUtils.copyPackage(
                mOriginInfo.mFile.getAbsolutePath(), mCodeFile);
        if (ret != PackageManager.INSTALL_SUCCEEDED) {
            Slog.e(TAG, "Failed to copy package");
            return ret;
        }

        final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
        final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
        NativeLibraryHelper.Handle handle = null;
        try {
            handle = NativeLibraryHelper.Handle.create(mCodeFile);
            ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
                    mAbiOverride, isIncremental);
        } catch (IOException e) {
            Slog.e(TAG, "Copying native libraries failed", e);
            ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
        } finally {
            IoUtils.closeQuietly(handle);
        }

        return ret;
    }

    int doPreInstall(int status) {
        if (status != PackageManager.INSTALL_SUCCEEDED) {
            cleanUp();
        }
        return status;
    }

    @Override
    boolean doRename(int status, ParsedPackage parsedPackage) {
        if (status != PackageManager.INSTALL_SUCCEEDED) {
            cleanUp();
            return false;
        }

        final File targetDir = resolveTargetDir();
        final File beforeCodeFile = mCodeFile;
        final File afterCodeFile = PackageManagerService.getNextCodePath(targetDir,
                parsedPackage.getPackageName());

        if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
        final boolean onIncremental = mPm.mIncrementalManager != null
                && isIncrementalPath(beforeCodeFile.getAbsolutePath());
        try {
            makeDirRecursive(afterCodeFile.getParentFile(), 0775);
            if (onIncremental) {
                // Just link files here. The stage dir will be removed when the installation
                // session is completed.
                mPm.mIncrementalManager.linkCodePath(beforeCodeFile, afterCodeFile);
            } else {
                Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
            }
        } catch (IOException | ErrnoException e) {
            Slog.w(TAG, "Failed to rename", e);
            return false;
        }

        if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
            Slog.w(TAG, "Failed to restorecon");
            return false;
        }

        // Reflect the rename internally
        mCodeFile = afterCodeFile;

        // Reflect the rename in scanned details
        try {
            parsedPackage.setPath(afterCodeFile.getCanonicalPath());
        } catch (IOException e) {
            Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
            return false;
        }
        parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
                afterCodeFile, parsedPackage.getBaseApkPath()));
        parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
                afterCodeFile, parsedPackage.getSplitCodePaths()));

        return true;
    }

    // TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
    //  flow, we won't need this method anymore.
    private File resolveTargetDir() {
        boolean isStagedInstall = (mInstallFlags & INSTALL_STAGED) != 0;
        if (isStagedInstall) {
            return Environment.getDataAppDirectory(null);
        } else {
            return mCodeFile.getParentFile();
        }
    }

    int doPostInstall(int status, int uid) {
        if (status != PackageManager.INSTALL_SUCCEEDED) {
            cleanUp();
        }
        return status;
    }

    @Override
    String getCodePath() {
        return (mCodeFile != null) ? mCodeFile.getAbsolutePath() : null;
    }

    private boolean cleanUp() {
        if (mCodeFile == null || !mCodeFile.exists()) {
            return false;
        }
        mPm.removeCodePathLI(mCodeFile);
        return true;
    }

    void cleanUpResourcesLI() {
        // Try enumerating all code paths before deleting
        List<String> allCodePaths = Collections.EMPTY_LIST;
        if (mCodeFile != null && mCodeFile.exists()) {
            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
            final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
                    input.reset(), mCodeFile, /* flags */ 0);
            if (result.isSuccess()) {
                // Ignore error; we tried our best
                allCodePaths = result.getResult().getAllApkPaths();
            }
        }

        cleanUp();
        removeDexFiles(allCodePaths, mInstructionSets);
    }

    void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
        if (!allCodePaths.isEmpty()) {
            if (instructionSets == null) {
                throw new IllegalStateException("instructionSet == null");
            }
            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
            for (String codePath : allCodePaths) {
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    try {
                        mPm.mInstaller.rmdex(codePath, dexCodeInstructionSet);
                    } catch (Installer.InstallerException ignored) {
                    }
                }
            }
        }
    }

    boolean doPostDeleteLI(boolean delete) {
        // XXX err, shouldn't we respect the delete flag?
        cleanUpResourcesLI();
        return true;
    }
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.os.UserHandle;
import android.util.Slog;

import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.TAG;

abstract class HandlerParams {
    /** User handle for the user requesting the information or installation. */
    private final UserHandle mUser;
    String mTraceMethod;
    int mTraceCookie;

    HandlerParams(UserHandle user) {
        mUser = user;
    }

    UserHandle getUser() {
        return mUser;
    }

    HandlerParams setTraceMethod(String traceMethod) {
        mTraceMethod = traceMethod;
        return this;
    }

    HandlerParams setTraceCookie(int traceCookie) {
        mTraceCookie = traceCookie;
        return this;
    }

    final void startCopy() {
        if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
        handleStartCopy();
        handleReturnCode();
    }

    abstract void handleStartCopy();
    abstract void handleReturnCode();
}
+43 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import android.content.pm.IPackageLoadingProgressCallback;

/**
 * Loading progress callback, used to listen for progress changes and update package setting
 */
final class IncrementalProgressListener extends IPackageLoadingProgressCallback.Stub {
    private final String mPackageName;
    private final PackageManagerService mPm;
    IncrementalProgressListener(String packageName, PackageManagerService pm) {
        mPackageName = packageName;
        mPm = pm;
    }

    @Override
    public void onPackageLoadingProgressChanged(float progress) {
        final PackageSetting ps;
        synchronized (mPm.mLock) {
            ps = mPm.mSettings.getPackageLPr(mPackageName);
            if (ps == null) {
                return;
            }
            ps.setLoadingProgress(progress);
        }
    }
}
Loading