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

Commit 3e62b8f7 authored by Nikita Ioffe's avatar Nikita Ioffe
Browse files

Fix PackageManager query API's related to rebootless APEX updates

There were two bugs:

1. In case of the first update, ApexManager removed information about
  pre-installed version of the APEX.
2. After an update, getPackageInfo cache wasn't invalidated, which
  resulted in getPackageInfo returning stale information.

Bug: 193085724
Test: atest ApexManagerTest
Test: atest StagedInstallInternalTest
Change-Id: I6df7b296cd5d83c93524178f1546855747ea6b07
parent 24e3ed6e
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -1051,9 +1051,13 @@ public abstract class ApexManager {
                final ParsedPackage parsedPackage2 = packageParser.parsePackage(
                        new File(apexInfo.modulePath), flags, /* useCaches= */ false);
                final PackageInfo finalApexPkg = PackageInfoWithoutStateUtils.generate(
                        parsedPackage, apexInfo, flags);
                        parsedPackage2, apexInfo, flags);
                // Installation was successful, time to update mAllPackagesCache
                synchronized (mLock) {
                    if (isFactory(existingApexPkg)) {
                        existingApexPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
                        mAllPackagesCache.add(finalApexPkg);
                    } else {
                        for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
                            if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
                                mAllPackagesCache.set(i, finalApexPkg);
@@ -1061,6 +1065,7 @@ public abstract class ApexManager {
                            }
                        }
                    }
                }
            } catch (RemoteException e) {
                throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                        "apexservice not available");
+1 −0
Original line number Diff line number Diff line
@@ -17362,6 +17362,7 @@ public class PackageManagerService extends IPackageManager.Stub
        } catch (PackageManagerException e) {
            request.installResult.setError("APEX installation failed", e);
        }
        invalidatePackageInfoCache();
        notifyInstallObserver(request.installResult, request.args.observer);
    }
+52 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -349,9 +350,9 @@ public class ApexManagerTest {
    }

    @Test
    public void testInstallPackage() throws Exception {
    public void testInstallPackage_activeOnSystem() throws Exception {
        ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
                /* isFactory= */ false, extractResource("test.apex_rebootless_v1",
                /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
                  "test.rebootless_apex_v1.apex"));
        when(mApexService.getAllPackages()).thenReturn(new ApexInfo[]{activeApexInfo});
        mApexManager.scanApexPackagesTraced(mPackageParser2,
@@ -369,6 +370,55 @@ public class ApexManagerTest {
                ApexManager.MATCH_ACTIVE_PACKAGE);
        assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
        assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
        assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
        assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
            .isEqualTo(ApplicationInfo.FLAG_INSTALLED);

        PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
                ApexManager.MATCH_FACTORY_PACKAGE);
        assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(activeApexInfo.modulePath);
        assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
        assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
            .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
        assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
    }

    @Test
    public void testInstallPackage_activeOnData() throws Exception {
        ApexInfo factoryApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ false,
                /* isFactory= */ true, extractResource("test.apex_rebootless_v1",
                  "test.rebootless_apex_v1.apex"));
        ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
                /* isFactory= */ false, extractResource("test.apex.rebootless@1",
                  "test.rebootless_apex_v1.apex"));
        when(mApexService.getAllPackages())
                .thenReturn(new ApexInfo[]{factoryApexInfo, activeApexInfo});
        mApexManager.scanApexPackagesTraced(mPackageParser2,
                ParallelPackageParser.makeExecutorService());

        File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
        ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
                /* isFactory= */ false, finalApex);
        when(mApexService.installAndActivatePackage(anyString())).thenReturn(newApexInfo);

        File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
        mApexManager.installPackage(installedApex, mPackageParser2);

        PackageInfo newInfo = mApexManager.getPackageInfo("test.apex.rebootless",
                ApexManager.MATCH_ACTIVE_PACKAGE);
        assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
        assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
        assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
        assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
            .isEqualTo(ApplicationInfo.FLAG_INSTALLED);

        PackageInfo factoryInfo = mApexManager.getPackageInfo("test.apex.rebootless",
                ApexManager.MATCH_FACTORY_PACKAGE);
        assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(factoryApexInfo.modulePath);
        assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
        assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
            .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
        assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
    }

    @Test
+31 −0
Original line number Diff line number Diff line
@@ -212,6 +212,28 @@ public class StagedInstallInternalTest {
            assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
        }

        TestApp apex1 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 1,
                /* isApex= */ true, "test.rebootless_apex_v1.apex");
        Install.single(apex1).commit();

        {
            PackageInfo apex = pm.getPackageInfo("test.apex.rebootless", PackageManager.MATCH_APEX);
            assertThat(apex.getLongVersionCode()).isEqualTo(1);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM).isEqualTo(0);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
                    .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
            assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
        }
        {
            PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
                    PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
            assertThat(apex.getLongVersionCode()).isEqualTo(1);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
                    .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
            assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
        }

        TestApp apex2 = new TestApp("TestRebootlessApexV1", "test.apex.rebootless", 2,
                /* isApex= */ true, "test.rebootless_apex_v2.apex");
        Install.single(apex2).commit();
@@ -224,6 +246,15 @@ public class StagedInstallInternalTest {
                    .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
            assertThat(apex.applicationInfo.sourceDir).startsWith("/data/apex/active");
        }
        {
            PackageInfo apex = pm.getPackageInfo("test.apex.rebootless",
                    PackageManager.MATCH_APEX | PackageManager.MATCH_FACTORY_ONLY);
            assertThat(apex.getLongVersionCode()).isEqualTo(1);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
                    .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
            assertThat(apex.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED).isEqualTo(0);
            assertThat(apex.applicationInfo.sourceDir).startsWith("/system/apex");
        }
    }

    private static void assertSessionFailedWithMessage(int sessionId, String msg) {