Merge "Add a service for reporting runtime debug info"
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();
|
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
|
// 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
|
// 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.
|
// this check when mOnlyCore == true, so we don't enable the service in this case.
|
||||||
|
|||||||
Reference in New Issue
Block a user