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

Commit aa0a453d authored by Calin Juravle's avatar Calin Juravle Committed by Automerger Merge Worker
Browse files

Merge changes from topic "server-reporting" into rvc-dev am: 11bdb5df am: b32e288a

Change-Id: Idb5f2c8988c6748b5d9bba40d5208c278f2f8107
parents e7704c35 b32e288a
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -9684,6 +9684,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) {
+47 −9
Original line number Diff line number Diff line
@@ -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;
                }

@@ -216,6 +221,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
@@ -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
+83 −0
Original line number Diff line number Diff line
/*
 * 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;

    private 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.
        }
    }

    /**
     * Configures system server dex file reporting.
     * <p>The method will install a reporter in the BaseDexClassLoader and also
     * force the reporting of any dex files already loaded by the system server.
     */
    public static void configureSystemServerDexReporter(IPackageManager pm) {
        Slog.i(TAG, "Configuring system server dex reporter");

        SystemServerDexLoadReporter reporter = new SystemServerDexLoadReporter(pm);
        BaseDexClassLoader.setReporter(reporter);
        ClassLoader currrentClassLoader = reporter.getClass().getClassLoader();
        if (currrentClassLoader instanceof BaseDexClassLoader) {
            ((BaseDexClassLoader) currrentClassLoader).reportClassLoaderChain();
        } else {
            Slog.wtf(TAG, "System server class loader is not a BaseDexClassLoader. type="
                    + currrentClassLoader.getClass().getName());
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -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;
@@ -837,6 +838,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.
        SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService);

        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        t.traceEnd();
+25 −0
Original line number Diff line number Diff line
@@ -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) {