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

Commit 00fa2c04 authored by Songchun Fan's avatar Songchun Fan
Browse files

[pm] link new splits to old dirs for DONT_KILL installs

For DONT_KILL installs, it's possible that apps use old code paths to
access new splits. This CL links newly added splits back to all the old
code paths.

BUG: 291212866
Test: manual; atest InstallDontKillTest

Change-Id: I6815eaa872fa58e321efccbfb19d42e94795015e
parent f8a66757
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2894,6 +2894,12 @@ final class InstallPackageHelper {
                    // code is loaded by a new Activity before ApplicationInfo changes have
                    // propagated to all application threads.
                    mPm.scheduleDeferredNoKillPostDelete(args);
                    if (Flags.improveInstallDontKill()) {
                        synchronized (mPm.mInstallLock) {
                            PackageManagerServiceUtils.linkSplitsToOldDirs(mPm.mInstaller,
                                    packageName, pkgSetting.getPath(), pkgSetting.getOldPaths());
                        }
                    }
                } else {
                    mRemovePackageHelper.cleanUpResources(packageName, args.getCodeFile(),
                            args.getInstructionSets());
+5 −3
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.internal.util.XmlUtils.writeUriAttribute;
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
import static com.android.server.pm.PackageManagerService.DEFAULT_FILE_ACCESS_MODE;
import static com.android.server.pm.PackageManagerServiceUtils.isInstalledByAdb;
import static com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;

@@ -1831,7 +1832,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            try {
                Os.link(path, sourcePath);
                // Grant READ access for APK to be read successfully
                Os.chmod(sourcePath, 0644);
                Os.chmod(sourcePath, DEFAULT_FILE_ACCESS_MODE);
            } catch (ErrnoException e) {
                e.rethrowAsIOException();
            }
@@ -1900,7 +1901,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

            // If file is app metadata then set permission to 0640 to deny user read access since it
            // might contain sensitive information.
            int mode = name.equals(APP_METADATA_FILE_NAME) ? APP_METADATA_FILE_ACCESS_MODE : 0644;
            int mode = name.equals(APP_METADATA_FILE_NAME)
                    ? APP_METADATA_FILE_ACCESS_MODE : DEFAULT_FILE_ACCESS_MODE;
            ParcelFileDescriptor targetPfd = openTargetInternal(target.getAbsolutePath(),
                    O_CREAT | O_WRONLY, mode);
            Os.chmod(target.getAbsolutePath(), mode);
@@ -4245,7 +4247,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
            }
            try {
                Os.chmod(tmpFile.getAbsolutePath(), 0644);
                Os.chmod(tmpFile.getAbsolutePath(), DEFAULT_FILE_ACCESS_MODE);
            } catch (ErrnoException e) {
                throw new IOException("Failed to chmod " + tmpFile);
            }
+2 −0
Original line number Diff line number Diff line
@@ -593,6 +593,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService

    static final String APP_METADATA_FILE_NAME = "app.metadata";

    static final int DEFAULT_FILE_ACCESS_MODE = 0644;

    final Handler mHandler;
    final Handler mBackgroundHandler;

+75 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
import static com.android.server.pm.PackageManagerService.DEBUG_PREFERRED;
import static com.android.server.pm.PackageManagerService.DEFAULT_FILE_ACCESS_MODE;
import static com.android.server.pm.PackageManagerService.RANDOM_CODEPATH_PREFIX;
import static com.android.server.pm.PackageManagerService.RANDOM_DIR_PREFIX;
import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME;
@@ -69,6 +70,7 @@ import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Process;
import android.os.SELinux;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
@@ -129,10 +131,12 @@ import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
@@ -853,7 +857,7 @@ public class PackageManagerServiceUtils {
            FileUtils.copy(fileIn, outputStream);
            // Flush anything in buffer before chmod, because any writes after chmod will fail.
            outputStream.flush();
            Os.fchmod(outputStream.getFD(), 0644);
            Os.fchmod(outputStream.getFD(), DEFAULT_FILE_ACCESS_MODE);
            atomicFile.finishWrite(outputStream);
            return PackageManager.INSTALL_SUCCEEDED;
        } catch (IOException e) {
@@ -1081,8 +1085,8 @@ public class PackageManagerServiceUtils {

        final File targetFile = new File(targetDir, targetName);
        final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
                O_RDWR | O_CREAT, 0644);
        Os.chmod(targetFile.getAbsolutePath(), 0644);
                O_RDWR | O_CREAT, DEFAULT_FILE_ACCESS_MODE);
        Os.chmod(targetFile.getAbsolutePath(), DEFAULT_FILE_ACCESS_MODE);
        FileInputStream source = null;
        try {
            source = new FileInputStream(sourcePath);
@@ -1552,4 +1556,72 @@ public class PackageManagerServiceUtils {
    public static boolean isInstalledByAdb(String initiatingPackageName) {
        return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName);
    }

    public static void linkSplitsToOldDirs(@NonNull Installer installer,
                                           @NonNull String packageName,
                                           @NonNull File newPath,
                                           @Nullable Set<File> oldPaths) {
        if (oldPaths == null || oldPaths.isEmpty()) {
            return;
        }
        if (IncrementalManager.isIncrementalPath(newPath.getPath())) {
            //TODO(b/291212866): handle incremental installs
            return;
        }
        final File[] filesInNewPath = newPath.listFiles();
        if (filesInNewPath == null || filesInNewPath.length == 0) {
            return;
        }
        final List<String> splitApkNames = new ArrayList<String>();
        for (int i = 0; i < filesInNewPath.length; i++) {
            if (!filesInNewPath[i].isDirectory() && filesInNewPath[i].toString().endsWith(".apk")) {
                splitApkNames.add(filesInNewPath[i].getName());
            }
        }
        final int numSplits = splitApkNames.size();
        if (numSplits == 0) {
            return;
        }
        for (File oldPath : oldPaths) {
            if (!oldPath.exists()) {
                continue;
            }
            for (int i = 0; i < numSplits; i++) {
                final String splitApkName = splitApkNames.get(i);
                final File linkedSplit = new File(oldPath, splitApkName);
                if (linkedSplit.exists()) {
                    if (DEBUG) {
                        Slog.d(PackageManagerService.TAG, "Skipping existing linked split <"
                                + linkedSplit + ">");
                    }
                    continue;
                }
                final File sourceSplit = new File(newPath, splitApkName);
                try {
                    installer.linkFile(packageName, splitApkName,
                            newPath.getAbsolutePath(), oldPath.getAbsolutePath());
                    if (DEBUG) {
                        Slog.d(PackageManagerService.TAG, "Linked <"
                                + sourceSplit + "> to <" + linkedSplit + ">");
                    }
                } catch (Installer.InstallerException e) {
                    Slog.w(PackageManagerService.TAG, "Failed to link split <"
                            + sourceSplit + " > to <" + linkedSplit + ">", e);
                    continue;
                }
                try {
                    Os.chmod(linkedSplit.getAbsolutePath(), DEFAULT_FILE_ACCESS_MODE);
                } catch (ErrnoException e) {
                    Slog.w(PackageManagerService.TAG, "Failed to set mode for linked split <"
                            + linkedSplit + ">", e);
                    continue;
                }
                if (!SELinux.restorecon(linkedSplit)) {
                    Slog.w(PackageManagerService.TAG, "Failed to restorecon for linked split <"
                            + linkedSplit + ">");
                }
            }
        }
        //TODO(b/291212866): support native libs
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
import static android.content.pm.PackageManager.RESTRICTION_NONE;

import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
import static com.android.server.pm.PackageManagerService.DEFAULT_FILE_ACCESS_MODE;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;

import android.accounts.IAccountManager;
@@ -2347,7 +2348,7 @@ class PackageManagerShellCommand extends ShellCommand {
                Streams.copy(inStream, outStream);
            }
            // Give read permissions to the other group.
            Os.chmod(outputProfilePath, /*mode*/ 0644 );
            Os.chmod(outputProfilePath, /*mode*/ DEFAULT_FILE_ACCESS_MODE);
        } catch (IOException | ErrnoException e) {
            pw.println("Error when reading the profile fd: " + e.getMessage());
            e.printStackTrace(pw);
Loading