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
This commit is contained in:
Nikita Ioffe
2021-07-10 02:27:51 +01:00
parent 24e3ed6e78
commit 3e62b8f748
4 changed files with 94 additions and 7 deletions

View File

@@ -1051,13 +1051,18 @@ 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) {
for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
if (mAllPackagesCache.get(i).equals(existingApexPkg)) {
mAllPackagesCache.set(i, finalApexPkg);
break;
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);
break;
}
}
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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) {