summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java16
-rw-r--r--services/core/java/com/android/server/pm/dex/DexManager.java56
-rw-r--r--services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java64
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java25
5 files changed, 158 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f96ab1d9a042..fd5905285009 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9679,6 +9679,20 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
String loaderIsa) {
+ if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
+ && Binder.getCallingUid() != Process.SYSTEM_UID) {
+ Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
+ + Binder.getCallingUid());
+ // Do not record dex loads from processes pretending to be system server.
+ // Only the system server should be assigned the package "android", so reject calls
+ // that don't satisfy the constraint.
+ //
+ // notifyDexLoad is a PM API callable from the app process. So in theory, apps could
+ // craft calls to this API and pretend to be system server. Doing so poses no particular
+ // danger for dex load reporting or later dexopt, however it is a sensible check to do
+ // in order to verify the expectations.
+ return;
+ }
int userId = UserHandle.getCallingUserId();
ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
if (ai == null) {
@@ -11305,7 +11319,7 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
parsedPackage.getPackageName() + " " +
AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage)
- + ", "
+ + ", "
+ AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage));
}
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index e8765ad973f3..ebdf85691e58 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -17,13 +17,17 @@
package com.android.server.pm.dex;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static java.util.function.Function.identity;
+
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
+import android.content.pm.PackagePartitions;
import android.os.FileUtils;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -67,13 +71,12 @@ import java.util.zip.ZipEntry;
*/
public class DexManager {
private static final String TAG = "DexManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
"pm.dexopt.priv-apps-oob-list";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
private final Context mContext;
// Maps package name to code locations.
@@ -178,12 +181,14 @@ public class DexManager {
boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
- if (primaryOrSplit && !isUsedByOtherApps) {
+ if (primaryOrSplit && !isUsedByOtherApps
+ && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) {
// If the dex file is the primary apk (or a split) and not isUsedByOtherApps
// do not record it. This case does not bring any new usable information
// and can be safely skipped.
// Note this is just an optimization that makes things easier to read in the
// package-dex-use file since we don't need to pollute it with redundant info.
+ // However, we always record system server packages.
continue;
}
@@ -217,6 +222,23 @@ public class DexManager {
}
/**
+ * Check if the dexPath belongs to system server.
+ * System server can load code from different location, so we cast a wide-net here, and
+ * assume that if the paths is on any of the registered system partitions then it can be loaded
+ * by system server.
+ */
+ private boolean isSystemServerDexPathSupportedForOdex(String dexPath) {
+ ArrayList<PackagePartitions.SystemPartition> partitions =
+ PackagePartitions.getOrderedPartitions(identity());
+ for (int i = 0; i < partitions.size(); i++) {
+ if (partitions.get(i).containsPath(dexPath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Read the dex usage from disk and populate the code cache locations.
* @param existingPackages a map containing information about what packages
* are available to what users. Only packages in this list will be
@@ -607,12 +629,6 @@ public class DexManager {
*/
private DexSearchResult getDexPackage(
ApplicationInfo loadingAppInfo, String dexPath, int userId) {
- // Ignore framework code.
- // TODO(calin): is there a better way to detect it?
- if (dexPath.startsWith("/system/framework/")) {
- return new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND);
- }
-
// First, check if the package which loads the dex file actually owns it.
// Most of the time this will be true and we can return early.
PackageCodeLocations loadingPackageCodeLocations =
@@ -635,6 +651,28 @@ public class DexManager {
}
}
+ // We could not find the owning package amongst regular apps.
+ // If the loading package is system server, see if the dex file resides
+ // on any of the potentially system server owning location and if so,
+ // assuming system server ownership.
+ //
+ // Note: We don't have any way to detect which code paths are actually
+ // owned by system server. We can only assume that such paths are on
+ // system partitions.
+ if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) {
+ if (isSystemServerDexPathSupportedForOdex(dexPath)) {
+ // We record system server dex files as secondary dex files.
+ // The reason is that we only record the class loader context for secondary dex
+ // files and we expect that all primary apks are loaded with an empty class loader.
+ // System server dex files may be loaded in non-empty class loader so we need to
+ // keep track of their context.
+ return new DexSearchResult(PLATFORM_PACKAGE_NAME, DEX_SEARCH_FOUND_SECONDARY);
+ } else {
+ Slog.wtf(TAG, "System server loads dex files outside paths supported for odex: "
+ + dexPath);
+ }
+ }
+
if (DEBUG) {
// TODO(calin): Consider checking for /data/data symlink.
// /data/data/ symlinks /data/user/0/ and there's nothing stopping apps
diff --git a/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java
new file mode 100644
index 000000000000..c090253cbbb1
--- /dev/null
+++ b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.dex;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.util.Map;
+
+/**
+ * Reports dex file use to the package manager on behalf of system server.
+ */
+public class SystemServerDexLoadReporter implements BaseDexClassLoader.Reporter {
+ private static final String TAG = "SystemServerDexLoadReporter";
+
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final IPackageManager mPackageManager;
+
+ public SystemServerDexLoadReporter(IPackageManager pm) {
+ mPackageManager = pm;
+ }
+
+ @Override
+ public void report(Map<String, String> classLoaderContextMap) {
+ if (DEBUG) {
+ Slog.i(TAG, "Reporting " + classLoaderContextMap);
+ }
+ if (classLoaderContextMap.isEmpty()) {
+ Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap");
+ return;
+ }
+
+ try {
+ mPackageManager.notifyDexLoad(
+ PLATFORM_PACKAGE_NAME,
+ classLoaderContextMap,
+ VMRuntime.getRuntime().vmInstructionSet());
+ } catch (RemoteException ignored) {
+ // We're in system server, it can't happen.
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2a914ecf4db6..61a12a53eb77 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -136,6 +136,7 @@ import com.android.server.pm.OtaDexoptService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.ShortcutService;
import com.android.server.pm.UserManagerService;
+import com.android.server.pm.dex.SystemServerDexLoadReporter;
import com.android.server.policy.PermissionPolicyService;
import com.android.server.policy.PhoneWindowManager;
import com.android.server.policy.role.LegacyRoleResolutionPolicy;
@@ -171,6 +172,7 @@ import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowManagerGlobalLock;
import com.android.server.wm.WindowManagerService;
+import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
import com.google.android.startop.iorap.IorapForwardingService;
@@ -839,6 +841,11 @@ public final class SystemServer {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
+ // Now that the package manager has started, register the dex load reporter to capture any
+ // dex files loaded by system server.
+ // These dex files will be optimized by the BackgroundDexOptService.
+ BaseDexClassLoader.setReporter(new SystemServerDexLoadReporter(mPackageManagerService));
+
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index d69e1b8786b4..8398585ca74a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -85,6 +85,9 @@ public class DexManagerTests {
private TestData mBarUser0UnsupportedClassLoader;
private TestData mBarUser0DelegateLastClassLoader;
+ private TestData mSystemServerJar;
+ private TestData mSystemServerJarInvalid;
+
private int mUser0;
private int mUser1;
@@ -108,6 +111,9 @@ public class DexManagerTests {
mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0,
DELEGATE_LAST_CLASS_LOADER_NAME);
+ mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+ mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
+
mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null,
mInstaller, mInstallLock);
@@ -587,6 +593,25 @@ public class DexManagerTests {
assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
}
+
+ @Test
+ public void testNotifySystemServerUse() {
+ List<String> dexFiles = new ArrayList<String>();
+ dexFiles.add("/system/framework/foo");
+ notifyDexLoad(mSystemServerJar, dexFiles, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
+ assertIsUsedByOtherApps(mSystemServerJar, pui, false);
+ }
+
+ @Test
+ public void testNotifySystemServerInvalidUse() {
+ List<String> dexFiles = new ArrayList<String>();
+ dexFiles.add("/data/foo");
+ notifyDexLoad(mSystemServerJarInvalid, dexFiles, mUser0);
+ assertNoUseInfo(mSystemServerJarInvalid);
+ assertNoDclInfo(mSystemServerJarInvalid);
+ }
+
private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
String[] expectedContexts) {