diff options
| -rw-r--r-- | core/proto/android/service/runtime.proto | 40 | ||||
| -rw-r--r-- | services/core/java/com/android/server/RuntimeService.java | 173 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 8 |
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. |