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

Commit a2c8ed75 authored by Nikita Ioffe's avatar Nikita Ioffe Committed by Automerger Merge Worker
Browse files

Merge "apk-in-apex-cache 1/n: Fix isCacheUpToDate for apk-in-apex" into tm-dev...

Merge "apk-in-apex-cache 1/n: Fix isCacheUpToDate for apk-in-apex" into tm-dev am: 239f082d am: 1f788888

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17888926



Change-Id: I2fc05529181ba9e5a1695abe7225a3e87bf7279f
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 9bc1411d 1f788888
Loading
Loading
Loading
Loading
+46 −6
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import java.io.File;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -119,16 +120,18 @@ public abstract class ApexManager {
        @Nullable public final String apexModuleName;
        public final File apexDirectory;
        public final File preInstalledApexPath;
        public final File apexFile;

        private ActiveApexInfo(File apexDirectory, File preInstalledApexPath) {
            this(null, apexDirectory, preInstalledApexPath);
        private ActiveApexInfo(File apexDirectory, File preInstalledApexPath, File apexFile) {
            this(null, apexDirectory, preInstalledApexPath, apexFile);
        }

        private ActiveApexInfo(@Nullable String apexModuleName, File apexDirectory,
                File preInstalledApexPath) {
                File preInstalledApexPath, File apexFile) {
            this.apexModuleName = apexModuleName;
            this.apexDirectory = apexDirectory;
            this.preInstalledApexPath = preInstalledApexPath;
            this.apexFile = apexFile;
        }

        private ActiveApexInfo(ApexInfo apexInfo) {
@@ -136,7 +139,8 @@ public abstract class ApexManager {
                    apexInfo.moduleName,
                    new File(Environment.getApexDirectory() + File.separator
                            + apexInfo.moduleName),
                    new File(apexInfo.preinstalledModulePath));
                    new File(apexInfo.preinstalledModulePath),
                    new File(apexInfo.modulePath));
        }
    }

@@ -427,6 +431,15 @@ public abstract class ApexManager {
     */
    public abstract List<ApexSystemServiceInfo> getApexSystemServices();

    /**
     * Returns an APEX file backing the mount point {@code file} is located on, or {@code null} if
     * {@code file} doesn't belong to a {@code /apex} mount point.
     *
     * <p>Also returns {@code null} if device doesn't support updatable APEX packages.
     */
    @Nullable
    public abstract File getBackingApexFile(@NonNull File file);

    /**
     * Dumps various state information to the provided {@link PrintWriter} object.
     *
@@ -451,6 +464,7 @@ public abstract class ApexManager {
    protected static class ApexManagerImpl extends ApexManager {
        private final Object mLock = new Object();

        // TODO(ioffe): this should be either List or ArrayMap.
        @GuardedBy("mLock")
        private Set<ActiveApexInfo> mActiveApexInfosCache;

@@ -1184,6 +1198,25 @@ public abstract class ApexManager {
            }
        }

        @Override
        public File getBackingApexFile(File file) {
            Path path = file.toPath();
            if (!path.startsWith(Environment.getApexDirectory().toPath())) {
                return null;
            }
            if (path.getNameCount() < 2) {
                return null;
            }
            String moduleName = file.toPath().getName(1).toString();
            final List<ActiveApexInfo> apexes = getActiveApexInfos();
            for (int i = 0; i < apexes.size(); i++) {
                if (apexes.get(i).apexModuleName.equals(moduleName)) {
                    return apexes.get(i).apexFile;
                }
            }
            return null;
        }

        /**
         * Dump information about the packages contained in a particular cache
         * @param packagesCache the cache to print information about.
@@ -1274,7 +1307,8 @@ public abstract class ApexManager {
     * An implementation of {@link ApexManager} that should be used in case device does not support
     * updating APEX packages.
     */
    private static final class ApexManagerFlattenedApex extends ApexManager {
    @VisibleForTesting
    static final class ApexManagerFlattenedApex extends ApexManager {
        @Override
        public List<ActiveApexInfo> getActiveApexInfos() {
            // There is no apexd running in case of flattened apex
@@ -1293,7 +1327,8 @@ public abstract class ApexManager {
                                // In flattened configuration, init special-cases the art directory
                                // and bind-mounts com.android.art.debug to com.android.art.
                                && !file.getName().equals("com.android.art.debug")) {
                            result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
                            result.add(
                                    new ActiveApexInfo(file, Environment.getRootDirectory(), file));
                        }
                    }
                }
@@ -1478,6 +1513,11 @@ public abstract class ApexManager {
            return Collections.emptyList();
        }

        @Override
        public File getBackingApexFile(File file) {
            return null;
        }

        @Override
        void dump(PrintWriter pw, String packageName) {
            // No-op
+13 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm.parsing;

import android.annotation.NonNull;
import android.content.pm.PackageParserCacheHelper;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Parcel;
import android.system.ErrnoException;
@@ -27,6 +28,7 @@ import android.system.StructStat;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.ApexManager;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;

@@ -118,6 +120,17 @@ public class PackageCacher {
     */
    private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
        try {
            // In case packageFile is located on one of /apex mount points it's mtime will always be
            // 0. Instead, we can use mtime of the APEX file backing the corresponding mount point.
            if (packageFile.toPath().startsWith(Environment.getApexDirectory().toPath())) {
                File backingApexFile = ApexManager.getInstance().getBackingApexFile(packageFile);
                if (backingApexFile == null) {
                    Slog.w(TAG,
                            "Failed to find APEX file backing " + packageFile.getAbsolutePath());
                } else {
                    packageFile = backingApexFile;
                }
            }
            // NOTE: We don't use the File.lastModified API because it has the very
            // non-ideal failure mode of returning 0 with no excepions thrown.
            // The nio2 Files API is a little better but is considerably more expensive.
+43 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.apex.IApexService;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
@@ -503,6 +504,48 @@ public class ApexManagerTest {
                .isEqualTo(TEST_APEX_PKG);
    }

    @Test
    public void testGetBackingApexFiles() throws Exception {
        final ApexInfo apex = createApexInfoForTestPkg(true, true, 37);
        when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});

        final File backingApexFile = mApexManager.getBackingApexFile(
                new File("/apex/" + TEST_APEX_PKG + "/apk/App/App.apk"));
        assertThat(backingApexFile.getAbsolutePath()).isEqualTo(apex.modulePath);
    }

    @Test
    public void testGetBackingApexFile_fileNotOnApexMountPoint_returnsNull() throws Exception {
        File result = mApexManager.getBackingApexFile(
                new File("/data/local/tmp/whatever/does-not-matter"));
        assertThat(result).isNull();
    }

    @Test
    public void testGetBackingApexFiles_unknownApex_returnsNull() throws Exception {
        final ApexInfo apex = createApexInfoForTestPkg(true, true, 37);
        when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});

        final File backingApexFile = mApexManager.getBackingApexFile(
                new File("/apex/com.wrong.apex/apk/App"));
        assertThat(backingApexFile).isNull();
    }

    @Test
    public void testGetBackingApexFiles_topLevelApexDir_returnsNull() throws Exception {
        assertThat(mApexManager.getBackingApexFile(Environment.getApexDirectory())).isNull();
        assertThat(mApexManager.getBackingApexFile(new File("/apex/"))).isNull();
        assertThat(mApexManager.getBackingApexFile(new File("/apex//"))).isNull();
    }

    @Test
    public void testGetBackingApexFiles_flattenedApex() throws Exception {
        ApexManager flattenedApexManager = new ApexManager.ApexManagerFlattenedApex();
        final File backingApexFile = flattenedApexManager.getBackingApexFile(
                new File("/apex/com.android.apex.cts.shim/app/CtsShim/CtsShim.apk"));
        assertThat(backingApexFile).isNull();
    }

    private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
        File apexFile = extractResource(TEST_APEX_PKG,  TEST_APEX_FILE_NAME);
        ApexInfo apexInfo = new ApexInfo();