summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ryan Mitchell <rtmitchell@google.com> 2020-05-15 10:33:57 -0700
committer Ryan Mitchell <rtmitchell@google.com> 2020-05-28 16:06:30 -0700
commitd4e7f93df50950aff2f973c9c7e8408bd07ca2f6 (patch)
tree020c4f305924971c72498617c08eea3602dbcfa7
parent57e977a5859ff24f5ff909046dccde5bce341f6d (diff)
Install system app in greatest priority partition
On Pixel 2 devices, /product is a symlink to /system/product. The product partition has a higher partition precedence than the system partition so the app should be installed as a system app on the product partition. This change also unifies methods for checking whether a file is within a partition so we will paths will always be canonicalized before the check. Bug: 152522330 Test: update system app in system/product/privapp, uninstall updates, verify that the app was scanned as privileged Change-Id: I646a5f293b977a78daa2102b73f1d3122f774a2a
-rw-r--r--core/java/android/content/pm/PackagePartitions.java83
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java6
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfigParser.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java6
6 files changed, 66 insertions, 51 deletions
diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java
index 9b8396e340ea..653b9ec9e8f2 100644
--- a/core/java/android/content/pm/PackagePartitions.java
+++ b/core/java/android/content/pm/PackagePartitions.java
@@ -93,15 +93,23 @@ public class PackagePartitions {
return out;
}
+ private static File canonicalize(File path) {
+ try {
+ return path.getCanonicalFile();
+ } catch (IOException e) {
+ return path;
+ }
+ }
+
/** Represents a partition that contains application packages. */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public static class SystemPartition {
- @NonNull
- public final File folder;
-
@PartitionType
public final int type;
+ @NonNull
+ private final DeferredCanonicalFile mFolder;
+
@Nullable
private final DeferredCanonicalFile mAppFolder;
@@ -113,18 +121,18 @@ public class PackagePartitions {
private SystemPartition(@NonNull File folder, @PartitionType int type,
boolean containsPrivApp, boolean containsOverlay) {
- this.folder = folder;
this.type = type;
+ this.mFolder = new DeferredCanonicalFile(folder);
this.mAppFolder = new DeferredCanonicalFile(folder, "app");
- this.mPrivAppFolder = containsPrivApp ?
- new DeferredCanonicalFile(folder, "priv-app") : null;
- this.mOverlayFolder = containsOverlay ?
- new DeferredCanonicalFile(folder, "overlay") : null;
+ this.mPrivAppFolder = containsPrivApp ? new DeferredCanonicalFile(folder, "priv-app")
+ : null;
+ this.mOverlayFolder = containsOverlay ? new DeferredCanonicalFile(folder, "overlay")
+ : null;
}
public SystemPartition(@NonNull SystemPartition original) {
- this.folder = original.folder;
this.type = original.type;
+ this.mFolder = new DeferredCanonicalFile(original.mFolder.getFile());
this.mAppFolder = original.mAppFolder;
this.mPrivAppFolder = original.mPrivAppFolder;
this.mOverlayFolder = original.mOverlayFolder;
@@ -139,6 +147,12 @@ public class PackagePartitions {
partition.mOverlayFolder != null);
}
+ /** Returns the canonical folder of the partition. */
+ @NonNull
+ public File getFolder() {
+ return mFolder.getFile();
+ }
+
/** Returns the canonical app folder of the partition. */
@Nullable
public File getAppFolder() {
@@ -157,30 +171,29 @@ public class PackagePartitions {
return mOverlayFolder == null ? null : mOverlayFolder.getFile();
}
+ /** Returns whether the partition contains the specified file. */
+ public boolean containsPath(@NonNull String path) {
+ return containsFile(new File(path));
+ }
+
+ /** Returns whether the partition contains the specified file. */
+ public boolean containsFile(@NonNull File file) {
+ return FileUtils.contains(mFolder.getFile(), canonicalize(file));
+ }
+
/** Returns whether the partition contains the specified file in its priv-app folder. */
public boolean containsPrivApp(@NonNull File scanFile) {
- return FileUtils.contains(mPrivAppFolder.getFile(), scanFile);
+ return FileUtils.contains(mPrivAppFolder.getFile(), canonicalize(scanFile));
}
/** Returns whether the partition contains the specified file in its app folder. */
public boolean containsApp(@NonNull File scanFile) {
- return FileUtils.contains(mAppFolder.getFile(), scanFile);
+ return FileUtils.contains(mAppFolder.getFile(), canonicalize(scanFile));
}
/** Returns whether the partition contains the specified file in its overlay folder. */
public boolean containsOverlay(@NonNull File scanFile) {
- return FileUtils.contains(mOverlayFolder.getFile(), scanFile);
- }
-
- /** Returns whether the partition contains the specified file. */
- public boolean containsPath(@NonNull String path) {
- return path.startsWith(folder.getPath() + "/");
- }
-
- /** Returns whether the partition contains the specified file in its priv-app folder. */
- public boolean containsPrivPath(@NonNull String path) {
- return mPrivAppFolder != null
- && path.startsWith(mPrivAppFolder.getFile().getPath() + "/");
+ return FileUtils.contains(mOverlayFolder.getFile(), canonicalize(scanFile));
}
}
@@ -190,22 +203,24 @@ public class PackagePartitions {
* have the correct selinux policies.
*/
private static class DeferredCanonicalFile {
- private boolean mIsCanonical;
+ private boolean mIsCanonical = false;
+
+ @NonNull
private File mFile;
- private DeferredCanonicalFile(File dir, String fileName) {
+
+ private DeferredCanonicalFile(@NonNull File dir) {
+ mFile = dir;
+ }
+
+ private DeferredCanonicalFile(@NonNull File dir, @NonNull String fileName) {
mFile = new File(dir, fileName);
- mIsCanonical = false;
}
+ @NonNull
private File getFile() {
- if (mIsCanonical) {
- return mFile;
- }
- mIsCanonical = true;
- try {
- mFile = mFile.getCanonicalFile();
- } catch (IOException ignore) {
- // failed to look up canonical path, continue with original one
+ if (!mIsCanonical) {
+ mFile = canonicalize(mFile);
+ mIsCanonical = true;
}
return mFile;
}
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index fbef027ac37f..3b5cf487c8da 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -110,7 +110,9 @@ public class OverlayConfig {
} else {
// Rebase the system partitions and settings file on the specified root directory.
partitions = new ArrayList<>(PackagePartitions.getOrderedPartitions(
- p -> new OverlayPartition(new File(rootDirectory, p.folder.getPath()), p)));
+ p -> new OverlayPartition(
+ new File(rootDirectory, p.getFolder().getPath()),
+ p)));
}
boolean foundConfigFile = false;
@@ -143,7 +145,7 @@ public class OverlayConfig {
// Filter out overlays not present in the partition.
partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos);
for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) {
- if (!partition.containsPath(partitionOverlayInfos.get(j).path.getPath())) {
+ if (!partition.containsFile(partitionOverlayInfos.get(j).path)) {
partitionOverlayInfos.remove(j);
}
}
diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java
index 139607ff7196..a86e5950c2f6 100644
--- a/core/java/com/android/internal/content/om/OverlayConfigParser.java
+++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java
@@ -27,8 +27,8 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Xml;
-import com.android.internal.util.XmlUtils;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
+import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
@@ -154,7 +154,7 @@ final class OverlayConfigParser {
return POLICY_PRODUCT;
default:
throw new IllegalStateException("Unable to determine policy for "
- + partition.folder);
+ + partition.getFolder());
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index aa7a1ad2b47a..fd861b56b729 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2711,13 +2711,13 @@ public class PackageManagerService extends IPackageManager.Stub
return SCAN_AS_SYSTEM_EXT;
default:
throw new IllegalStateException("Unable to determine scan flag for "
- + partition.folder);
+ + partition.getFolder());
}
}
@Override
public String toString() {
- return folder.getAbsolutePath() + ":" + scanFlag;
+ return getFolder().getAbsolutePath() + ":" + scanFlag;
}
}
@@ -3283,7 +3283,7 @@ public class PackageManagerService extends IPackageManager.Stub
@ParseFlags int reparseFlags = 0;
@ScanFlags int rescanFlags = 0;
- for (int i1 = 0, size = mDirsToScanAsSystem.size(); i1 < size; i1++) {
+ for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i1);
if (partition.containsPrivApp(scanFile)) {
reparseFlags = systemParseFlags;
@@ -18681,7 +18681,7 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
ScanPartition sp = SYSTEM_PARTITIONS.get(i);
if (apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.folder.getAbsolutePath())) {
+ sp.getFolder().getAbsolutePath())) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
@@ -18777,23 +18777,23 @@ public class PackageManagerService extends IPackageManager.Stub
@Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
@Nullable PermissionsState origPermissionState, boolean writeSettings)
throws PackageManagerException {
+ final File codePath = new File(codePathString);
@ParseFlags int parseFlags =
mDefParseFlags
| PackageParser.PARSE_MUST_BE_APK
| PackageParser.PARSE_IS_SYSTEM_DIR;
@ScanFlags int scanFlags = SCAN_AS_SYSTEM;
- for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
+ for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = mDirsToScanAsSystem.get(i);
- if (partition.containsPath(codePathString)) {
+ if (partition.containsFile(codePath)) {
scanFlags |= partition.scanFlag;
- if (partition.containsPrivPath(codePathString)) {
+ if (partition.containsPrivApp(codePath)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
break;
}
}
- final File codePath = new File(codePathString);
final AndroidPackage pkg =
scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a5b1bf98cdb7..936ba7f3b097 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3235,7 +3235,7 @@ public final class Settings {
PackageManagerService.ScanPartition partition =
PackageManagerService.SYSTEM_PARTITIONS.get(index);
- File preferredDir = new File(partition.folder, "etc/preferred-apps");
+ File preferredDir = new File(partition.getFolder(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
continue;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 37c106094954..c4e25b53d5d5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -122,10 +122,8 @@ public class PackageManagerServiceTest {
final PackageManagerService.ScanPartition scanPartition =
PackageManagerService.SYSTEM_PARTITIONS.get(i);
for (int j = 0; j < appdir.length; j++) {
- String canonical = new File("/" + partitions[i]).getCanonicalPath();
- String path = String.format("%s/%s/A.apk", canonical, appdir[j]);
-
- Assert.assertEquals(j == 1 && i != 3, scanPartition.containsPrivPath(path));
+ File path = new File(String.format("%s/%s/A.apk", partitions[i], appdir[j]));
+ Assert.assertEquals(j == 1 && i != 3, scanPartition.containsPrivApp(path));
final int scanFlag = scanPartition.scanFlag;
Assert.assertEquals(i == 1, scanFlag == PackageManagerService.SCAN_AS_VENDOR);