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

Commit 549084ff authored by Jiakai Zhang's avatar Jiakai Zhang Committed by Android (Google) Code Review
Browse files

Merge changes I9be98ac0,Id90a7534,I7f0fd165 into main

* changes:
  Remove a wtf log from notifyDexLoad.
  Remove CompilerStats.
  Remove `DexOptHelper.reportBootDexopt`.
parents 7fb18cd3 79b292ea
Loading
Loading
Loading
Loading
+0 −295
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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;

import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;

import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.IndentingPrintWriter;

import libcore.io.IoUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * A class that collects, serializes and deserializes compiler-related statistics on a
 * per-package per-code-path basis.
 *
 * Currently used to track compile times.
 */
class CompilerStats extends AbstractStatsBase<Void> {

    private final static String COMPILER_STATS_VERSION_HEADER = "PACKAGE_MANAGER__COMPILER_STATS__";
    private final static int COMPILER_STATS_VERSION = 1;

    /**
     * Class to collect all stats pertaining to one package.
     */
    static class PackageStats {

        private final String packageName;

        /**
         * This map stores compile-times for all code paths in the package. The value
         * is in milliseconds.
         */
        private final Map<String, Long> compileTimePerCodePath;

        /**
         * @param packageName
         */
        public PackageStats(String packageName) {
            this.packageName = packageName;
            // We expect at least one element in here, but let's make it minimal.
            compileTimePerCodePath = new ArrayMap<>(2);
        }

        public String getPackageName() {
            return packageName;
        }

        /**
         * Return the recorded compile time for a given code path. Returns
         * 0 if there is no recorded time.
         */
        public long getCompileTime(String codePath) {
            String storagePath = getStoredPathFromCodePath(codePath);
            synchronized (compileTimePerCodePath) {
                Long l = compileTimePerCodePath.get(storagePath);
                if (l == null) {
                    return 0;
                }
                return l;
            }
        }

        public void setCompileTime(String codePath, long compileTimeInMs) {
            String storagePath = getStoredPathFromCodePath(codePath);
            synchronized (compileTimePerCodePath) {
                if (compileTimeInMs <= 0) {
                    compileTimePerCodePath.remove(storagePath);
                } else {
                    compileTimePerCodePath.put(storagePath, compileTimeInMs);
                }
            }
        }

        private static String getStoredPathFromCodePath(String codePath) {
            int lastSlash = codePath.lastIndexOf(File.separatorChar);
            return codePath.substring(lastSlash + 1);
        }

        public void dump(IndentingPrintWriter ipw) {
            synchronized (compileTimePerCodePath) {
                if (compileTimePerCodePath.size() == 0) {
                    ipw.println("(No recorded stats)");
                } else {
                    for (Map.Entry<String, Long> e : compileTimePerCodePath.entrySet()) {
                        ipw.println(" " + e.getKey() + " - " + e.getValue());
                    }
                }
            }
        }
    }

    private final Map<String, PackageStats> packageStats;

    public CompilerStats() {
        super("package-cstats.list", "CompilerStats_DiskWriter", /* lock */ false);
        packageStats = new HashMap<>();
    }

    public PackageStats getPackageStats(String packageName) {
        synchronized (packageStats) {
            return packageStats.get(packageName);
        }
    }

    public void setPackageStats(String packageName, PackageStats stats) {
        synchronized (packageStats) {
            packageStats.put(packageName, stats);
        }
    }

    public PackageStats createPackageStats(String packageName) {
        synchronized (packageStats) {
            PackageStats newStats = new PackageStats(packageName);
            packageStats.put(packageName, newStats);
            return newStats;
        }
    }

    public PackageStats getOrCreatePackageStats(String packageName) {
        synchronized (packageStats) {
            PackageStats existingStats = packageStats.get(packageName);
            if (existingStats != null) {
                return existingStats;
            }

            return createPackageStats(packageName);
        }
    }

    public void deletePackageStats(String packageName) {
        synchronized (packageStats) {
            packageStats.remove(packageName);
        }
    }

    // I/O

    // The encoding is simple:
    //
    // 1) The first line is a line consisting of the version header and the version number.
    //
    // 2) The rest of the file is package data.
    // 2.1) A package is started by any line not starting with "-";
    // 2.2) Any line starting with "-" is code path data. The format is:
    //      '-'{code-path}':'{compile-time}

    public void write(Writer out) {
        @SuppressWarnings("resource")
        FastPrintWriter fpw = new FastPrintWriter(out);

        fpw.print(COMPILER_STATS_VERSION_HEADER);
        fpw.println(COMPILER_STATS_VERSION);

        synchronized (packageStats) {
            for (PackageStats pkg : packageStats.values()) {
                synchronized (pkg.compileTimePerCodePath) {
                    if (!pkg.compileTimePerCodePath.isEmpty()) {
                        fpw.println(pkg.getPackageName());

                        for (Map.Entry<String, Long> e : pkg.compileTimePerCodePath.entrySet()) {
                            fpw.println("-" + e.getKey() + ":" + e.getValue());
                        }
                    }
                }
            }
        }

        fpw.flush();
    }

    public boolean read(Reader r) {
        synchronized (packageStats) {
            // TODO: Could make this a final switch, then we wouldn't have to synchronize over
            //       the whole reading.
            packageStats.clear();

            try {
                BufferedReader in = new BufferedReader(r);

                // Read header, do version check.
                String versionLine = in.readLine();
                if (versionLine == null) {
                    throw new IllegalArgumentException("No version line found.");
                } else {
                    if (!versionLine.startsWith(COMPILER_STATS_VERSION_HEADER)) {
                        throw new IllegalArgumentException("Invalid version line: " + versionLine);
                    }
                    int version = Integer.parseInt(
                            versionLine.substring(COMPILER_STATS_VERSION_HEADER.length()));
                    if (version != COMPILER_STATS_VERSION) {
                        // TODO: Upgrade older formats? For now, just reject and regenerate.
                        throw new IllegalArgumentException("Unexpected version: " + version);
                    }
                }

                // For simpler code, we ignore any data lines before the first package. We
                // collect it in a fake package.
                PackageStats currentPackage = new PackageStats("fake package");

                String s = null;
                while ((s = in.readLine()) != null) {
                    if (s.startsWith("-")) {
                        int colonIndex = s.indexOf(':');
                        if (colonIndex == -1 || colonIndex == 1) {
                            throw new IllegalArgumentException("Could not parse data " + s);
                        }
                        String codePath = s.substring(1, colonIndex);
                        long time = Long.parseLong(s.substring(colonIndex + 1));
                        currentPackage.setCompileTime(codePath, time);
                    } else {
                        currentPackage = getOrCreatePackageStats(s);
                    }
                }
            } catch (Exception e) {
                Log.e(PackageManagerService.TAG, "Error parsing compiler stats", e);
                return false;
            }

            return true;
        }
    }

    void writeNow() {
        writeNow(null);
    }

    boolean maybeWriteAsync() {
        return maybeWriteAsync(null);
    }

    @Override
    protected void writeInternal(Void data) {
        AtomicFile file = getFile();
        FileOutputStream f = null;

        try {
            f = file.startWrite();
            OutputStreamWriter osw = new OutputStreamWriter(f);
            write(osw);
            osw.flush();
            file.finishWrite(f);
        } catch (IOException e) {
            if (f != null) {
                file.failWrite(f);
            }
            Log.e(PackageManagerService.TAG, "Failed to write compiler stats", e);
        }
    }

    void read() {
        read((Void)null);
    }

    @Override
    protected void readInternal(Void data) {
        AtomicFile file = getFile();
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(file.openRead()));
            read(in);
        } catch (FileNotFoundException expected) {
        } finally {
            IoUtils.closeQuietly(in);
        }
    }
}
+0 −39
Original line number Diff line number Diff line
@@ -170,7 +170,6 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -417,7 +416,6 @@ public class ComputerEngine implements Computer {
    private final InstantAppResolverConnection mInstantAppResolverConnection;
    private final DefaultAppProvider mDefaultAppProvider;
    private final DomainVerificationManagerInternal mDomainVerificationManager;
    private final CompilerStats mCompilerStats;
    private final PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
    private final CrossProfileIntentResolverEngine mCrossProfileIntentResolverEngine;

@@ -467,7 +465,6 @@ public class ComputerEngine implements Computer {
        mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
        mDefaultAppProvider = args.service.getDefaultAppProvider();
        mDomainVerificationManager = args.service.mDomainVerificationManager;
        mCompilerStats = args.service.mCompilerStats;
        mExternalSourcesPolicy = args.service.mExternalSourcesPolicy;
        mCrossProfileIntentResolverEngine = new CrossProfileIntentResolverEngine(
                mUserManager, mDomainVerificationManager, mDefaultAppProvider, mContext);
@@ -3126,42 +3123,6 @@ public class ComputerEngine implements Computer {
                break;
            }

            case DumpState.DUMP_COMPILER_STATS:
            {
                final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
                if (dumpState.onTitlePrinted()) {
                    pw.println();
                }
                ipw.println("Compiler stats:");
                ipw.increaseIndent();
                Collection<? extends PackageStateInternal> pkgSettings;
                if (setting != null) {
                    pkgSettings = Collections.singletonList(setting);
                } else {
                    pkgSettings = mSettings.getPackages().values();
                }

                for (PackageStateInternal pkgSetting : pkgSettings) {
                    final AndroidPackage pkg = pkgSetting.getPkg();
                    if (pkg == null) {
                        continue;
                    }
                    final String pkgName = pkg.getPackageName();
                    ipw.println("[" + pkgName + "]");
                    ipw.increaseIndent();

                    final CompilerStats.PackageStats stats =
                            mCompilerStats.getPackageStats(pkgName);
                    if (stats == null) {
                        ipw.println("(No recorded stats)");
                    } else {
                        stats.dump(ipw);
                    }
                    ipw.decreaseIndent();
                }
                break;
            }

            case DumpState.DUMP_MESSAGES: {
                mSettings.dumpReadMessages(pw, dumpState);
                break;
+0 −62
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalManagerRegistry;
@@ -93,10 +92,6 @@ public final class DexOptHelper {
    private final PackageManagerService mPm;
    private final InstallScenarioHelper mInstallScenarioHelper;

    // Start time for the boot dexopt in performPackageDexOptUpgradeIfNeeded when ART Service is
    // used, to make it available to the onDexoptDone callback.
    private volatile long mBootDexoptStartTime;

    static {
        // Recycle the thread if it's not used for `keepAliveTime`.
        sDexoptExecutor.allowsCoreThreadTimeOut();
@@ -128,27 +123,10 @@ public final class DexOptHelper {

        Log.i(TAG, "Starting boot dexopt for reason " + reason);

        final long startTime = System.nanoTime();

        mBootDexoptStartTime = startTime;
        getArtManagerLocal()
                .onBoot(reason, null /* progressCallbackExecutor */, null /* progressCallback */);
    }

    private void reportBootDexopt(long startTime, int numDexopted, int numSkipped, int numFailed) {
        final int elapsedTimeSeconds =
                (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);

        final Computer newSnapshot = mPm.snapshotComputer();

        MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", numDexopted);
        MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", numSkipped);
        MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", numFailed);
        MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_total",
                numDexopted + numSkipped + numFailed);
        MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
    }

     /**
     * Requests that files preopted on a secondary system partition be copied to the data partition
     * if possible.  Note that the actual copying of the files is accomplished by init for security
@@ -258,46 +236,6 @@ public final class DexOptHelper {
         */
        @Override
        public void onDexoptDone(@NonNull DexoptResult result) {
            switch (result.getReason()) {
                case ReasonMapping.REASON_FIRST_BOOT:
                case ReasonMapping.REASON_BOOT_AFTER_OTA:
                case ReasonMapping.REASON_BOOT_AFTER_MAINLINE_UPDATE:
                    int numDexopted = 0;
                    int numSkipped = 0;
                    int numFailed = 0;
                    for (DexoptResult.PackageDexoptResult pkgRes :
                            result.getPackageDexoptResults()) {
                        switch (pkgRes.getStatus()) {
                            case DexoptResult.DEXOPT_PERFORMED:
                                numDexopted += 1;
                                break;
                            case DexoptResult.DEXOPT_SKIPPED:
                                numSkipped += 1;
                                break;
                            case DexoptResult.DEXOPT_FAILED:
                                numFailed += 1;
                                break;
                        }
                    }

                    reportBootDexopt(mBootDexoptStartTime, numDexopted, numSkipped, numFailed);
                    break;
            }

            for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) {
                CompilerStats.PackageStats stats =
                        mPm.getOrCreateCompilerPackageStats(pkgRes.getPackageName());
                for (DexoptResult.DexContainerFileDexoptResult dexRes :
                        pkgRes.getDexContainerFileDexoptResults()) {
                    stats.setCompileTime(
                            dexRes.getDexContainerFile(), dexRes.getDex2oatWallTimeMillis());
                }
            }

            synchronized (mPm.mLock) {
                mPm.mCompilerStats.maybeWriteAsync();
            }

            if (result.getReason().equals(ReasonMapping.REASON_INACTIVE)) {
                for (DexoptResult.PackageDexoptResult pkgRes : result.getPackageDexoptResults()) {
                    if (pkgRes.getStatus() == DexoptResult.DEXOPT_PERFORMED) {
+0 −7
Original line number Diff line number Diff line
@@ -245,8 +245,6 @@ final class DumpHelper {
                dumpState.setDump(DumpState.DUMP_VOLUMES);
            } else if ("dexopt".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_DEXOPT);
            } else if ("compiler-stats".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
            } else if ("changes".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_CHANGES);
            } else if ("service-permissions".equals(cmd)) {
@@ -529,11 +527,6 @@ final class DumpHelper {
            snapshot.dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
        }

        if (!checkin
                && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
            snapshot.dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
        }

        if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
                && packageName == null) {
            if (!checkin) {
+0 −1
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ public final class DumpState {
    public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
    public static final int DUMP_FROZEN = 1 << 19;
    public static final int DUMP_DEXOPT = 1 << 20;
    public static final int DUMP_COMPILER_STATS = 1 << 21;
    public static final int DUMP_CHANGES = 1 << 22;
    public static final int DUMP_VOLUMES = 1 << 23;
    public static final int DUMP_SERVICE_PERMISSIONS = 1 << 24;
Loading