summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Neil Fuller <nfuller@google.com> 2018-12-04 08:10:34 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-12-04 08:10:34 +0000
commit08cbafefdc4924e1619da99082e8af3b94cc9ab3 (patch)
tree5af3b5831d6e5488f25952cd602d1a805972d637
parent98c9cd7b206d881b9f9623a6e86121091a654582 (diff)
parentab0b81e9210edb68d0bff9e0428a6bd2d95b411d (diff)
Merge "Add a service for reporting runtime debug info"
-rw-r--r--core/proto/android/service/runtime.proto40
-rw-r--r--services/core/java/com/android/server/RuntimeService.java173
-rw-r--r--services/java/com/android/server/SystemServer.java8
3 files changed, 221 insertions, 0 deletions
diff --git a/core/proto/android/service/runtime.proto b/core/proto/android/service/runtime.proto
new file mode 100644
index 000000000000..ecbccef7a94c
--- /dev/null
+++ b/core/proto/android/service/runtime.proto
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+package android.service.runtime;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "RuntimeServiceProto";
+
+// Represents dumpsys info from RuntimeService.
+message RuntimeServiceInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Generic debug information to include.
+ repeated DebugEntryProto debug_entry = 1;
+}
+
+// A piece of key / value debug information.
+message DebugEntryProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string key = 1;
+
+ optional string string_value = 2;
+}
diff --git a/services/core/java/com/android/server/RuntimeService.java b/services/core/java/com/android/server/RuntimeService.java
new file mode 100644
index 000000000000..ccfac80d22a7
--- /dev/null
+++ b/services/core/java/com/android/server/RuntimeService.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.content.Context;
+import android.os.Binder;
+import android.service.runtime.DebugEntryProto;
+import android.service.runtime.RuntimeServiceInfoProto;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import libcore.timezone.TimeZoneDataFiles;
+import libcore.util.CoreLibraryDebug;
+import libcore.util.DebugInfo;
+
+import com.android.internal.util.DumpUtils;
+import com.android.timezone.distro.DistroException;
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.FileUtils;
+import com.android.timezone.distro.TimeZoneDistro;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * This service exists only as a "dumpsys" target which reports information about the status of the
+ * runtime and related libraries.
+ */
+public class RuntimeService extends Binder {
+
+ private static final String TAG = "RuntimeService";
+
+ private final Context mContext;
+
+ public RuntimeService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {
+ return;
+ }
+
+ boolean protoFormat = hasOption(args, "--proto");
+ ProtoOutputStream proto = null;
+
+ DebugInfo coreLibraryDebugInfo = CoreLibraryDebug.getDebugInfo();
+ addTimeZoneApkDebugInfo(coreLibraryDebugInfo);
+
+ if (protoFormat) {
+ proto = new ProtoOutputStream(fd);
+ reportTimeZoneInfoProto(coreLibraryDebugInfo, proto);
+ } else {
+ reportTimeZoneInfo(coreLibraryDebugInfo, pw);
+ }
+
+ if (protoFormat) {
+ proto.flush();
+ }
+ }
+
+ /** Returns {@code true} if {@code args} contains {@code arg}. */
+ private static boolean hasOption(String[] args, String arg) {
+ for (String opt : args) {
+ if (arg.equals(opt)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add information to {@link DebugInfo} about the time zone data supplied by the
+ * "Time zone updates via APK" feature.
+ */
+ private static void addTimeZoneApkDebugInfo(DebugInfo coreLibraryDebugInfo) {
+ // Add /data tz data set using the DistroVersion class (which libcore cannot use).
+ // This update mechanism will be removed after the time zone APEX is launched so this
+ // untidiness will disappear with it.
+ String debugKeyPrefix = "core_library.timezone.data_";
+ String versionFileName = TimeZoneDataFiles.getDataTimeZoneFile(
+ TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
+ addDistroVersionDebugInfo(versionFileName, debugKeyPrefix, coreLibraryDebugInfo);
+ }
+
+ /**
+ * Prints {@code coreLibraryDebugInfo} to {@code pw}.
+ *
+ * <p>If you change this method, make sure to modify
+ * {@link #reportTimeZoneInfoProto(DebugInfo, ProtoOutputStream)} as well.
+ */
+ private static void reportTimeZoneInfo(DebugInfo coreLibraryDebugInfo,
+ PrintWriter pw) {
+ pw.println("Core Library Debug Info: ");
+ for (DebugInfo.DebugEntry debugEntry : coreLibraryDebugInfo.getDebugEntries()) {
+ pw.print(debugEntry.getKey());
+ pw.print(": \"");
+ pw.print(debugEntry.getStringValue());
+ pw.println("\"");
+ }
+ }
+
+ /**
+ * Adds {@code coreLibraryDebugInfo} to {@code protoStream}.
+ *
+ * <p>If you change this method, make sure to modify
+ * {@link #reportTimeZoneInfo(DebugInfo, PrintWriter)}.
+ */
+ private static void reportTimeZoneInfoProto(
+ DebugInfo coreLibraryDebugInfo, ProtoOutputStream protoStream) {
+ for (DebugInfo.DebugEntry debugEntry : coreLibraryDebugInfo.getDebugEntries()) {
+ long entryToken = protoStream.start(RuntimeServiceInfoProto.DEBUG_ENTRY);
+ protoStream.write(DebugEntryProto.KEY, debugEntry.getKey());
+ protoStream.write(DebugEntryProto.STRING_VALUE, debugEntry.getStringValue());
+ protoStream.end(entryToken);
+ }
+ }
+
+ /**
+ * Adds version information to {@code debugInfo} from the distro_version file that may exist
+ * at {@code distroVersionFileName}. If the file does not exist or cannot be read this is
+ * reported as debug information too.
+ */
+ private static void addDistroVersionDebugInfo(String distroVersionFileName,
+ String debugKeyPrefix, DebugInfo debugInfo) {
+ File file = new File(distroVersionFileName);
+ String statusKey = debugKeyPrefix + "status";
+ if (file.exists()) {
+ try {
+ byte[] versionBytes =
+ FileUtils.readBytes(file, DistroVersion.DISTRO_VERSION_FILE_LENGTH);
+ DistroVersion distroVersion = DistroVersion.fromBytes(versionBytes);
+ String formatVersionString = distroVersion.formatMajorVersion + "."
+ + distroVersion.formatMinorVersion;
+ debugInfo.addStringEntry(statusKey, "OK")
+ .addStringEntry(debugKeyPrefix + "formatVersion", formatVersionString)
+ .addStringEntry(debugKeyPrefix + "rulesVersion",
+ distroVersion.rulesVersion)
+ .addStringEntry(debugKeyPrefix + "revision",
+ distroVersion.revision);
+ } catch (IOException | DistroException e) {
+ debugInfo.addStringEntry(statusKey, "ERROR");
+ debugInfo.addStringEntry(debugKeyPrefix + "exception_class",
+ e.getClass().getName());
+ debugInfo.addStringEntry(debugKeyPrefix + "exception_msg", e.getMessage());
+ logMessage("Error reading " + file, e);
+ }
+ } else {
+ debugInfo.addStringEntry(statusKey, "NOT_FOUND");
+ }
+ }
+
+ private static void logMessage(String msg, Throwable t) {
+ Slog.v(TAG, msg, t);
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 439f313e0f0a..80b0e6f4fca7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1419,6 +1419,14 @@ public final class SystemServer {
}
traceEnd();
+ traceBeginAndSlog("RuntimeService");
+ try {
+ ServiceManager.addService("runtime", new RuntimeService(context));
+ } catch (Throwable e) {
+ reportWtf("starting RuntimeService", e);
+ }
+ traceEnd();
+
// timezone.RulesManagerService will prevent a device starting up if the chain of trust
// required for safe time zone updates might be broken. RuleManagerService cannot do
// this check when mOnlyCore == true, so we don't enable the service in this case.