Merge "Add a service for reporting runtime debug info"
am: 08cbafefdc
Change-Id: I7964eb4c6a72f7d2a52f600cbb4c8e07736284fe
This commit is contained in:
40
core/proto/android/service/runtime.proto
Normal file
40
core/proto/android/service/runtime.proto
Normal file
@@ -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;
|
||||
}
|
||||
173
services/core/java/com/android/server/RuntimeService.java
Normal file
173
services/core/java/com/android/server/RuntimeService.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user