1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.protolog; 18 19 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.CACHE_UPDATER; 20 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH; 21 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH; 22 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LOG_GROUPS; 23 import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH; 24 25 import android.annotation.Nullable; 26 import android.os.ServiceManager; 27 import android.util.Log; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.protolog.common.IProtoLog; 31 import com.android.internal.protolog.common.IProtoLogGroup; 32 import com.android.internal.protolog.common.LogLevel; 33 import com.android.internal.protolog.common.ProtoLogToolInjected; 34 35 import java.io.File; 36 import java.util.TreeMap; 37 38 /** 39 * A service for the ProtoLog logging system. 40 */ 41 public class ProtoLogImpl { 42 private static final String LOG_TAG = "ProtoLogImpl"; 43 44 private static IProtoLog sServiceInstance = null; 45 46 @ProtoLogToolInjected(VIEWER_CONFIG_PATH) 47 private static String sViewerConfigPath; 48 49 @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH) 50 private static String sLegacyViewerConfigPath; 51 52 @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH) 53 private static String sLegacyOutputFilePath; 54 55 @ProtoLogToolInjected(LOG_GROUPS) 56 private static TreeMap<String, IProtoLogGroup> sLogGroups; 57 58 @ProtoLogToolInjected(CACHE_UPDATER) 59 private static ProtoLogCacheUpdater sCacheUpdater; 60 61 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ d(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)62 public static void d(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 63 getSingleInstance().log(LogLevel.DEBUG, group, messageHash, paramsMask, args); 64 } 65 66 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ v(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)67 public static void v(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 68 getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, args); 69 } 70 71 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ i(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)72 public static void i(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 73 getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, args); 74 } 75 76 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ w(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)77 public static void w(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 78 getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, args); 79 } 80 81 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ e(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)82 public static void e(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 83 getSingleInstance().log(LogLevel.ERROR, group, messageHash, paramsMask, args); 84 } 85 86 /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ wtf(IProtoLogGroup group, long messageHash, int paramsMask, Object... args)87 public static void wtf(IProtoLogGroup group, long messageHash, int paramsMask, Object... args) { 88 getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, args); 89 } 90 91 /** 92 * Should return true iff we should be logging to either protolog or logcat for this group 93 * and log level. 94 */ isEnabled(IProtoLogGroup group, LogLevel level)95 public static boolean isEnabled(IProtoLogGroup group, LogLevel level) { 96 return isEnabled(getSingleInstance(), group, level); 97 } 98 isEnabled( IProtoLog protoLogInstance, IProtoLogGroup group, LogLevel level)99 private static boolean isEnabled( 100 IProtoLog protoLogInstance, IProtoLogGroup group, LogLevel level) { 101 return protoLogInstance.isEnabled(group, level); 102 } 103 104 /** 105 * Returns the single instance of the ProtoLogImpl singleton class. 106 */ getSingleInstance()107 public static synchronized IProtoLog getSingleInstance() { 108 if (sServiceInstance == null) { 109 Log.i(LOG_TAG, "Setting up " + ProtoLogImpl.class.getSimpleName() + " with " 110 + "viewerConfigPath = " + sViewerConfigPath); 111 112 final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]); 113 if (android.tracing.Flags.perfettoProtologTracing()) { 114 var viewerConfigFile = new File(sViewerConfigPath); 115 if (!viewerConfigFile.exists()) { 116 // TODO(b/353530422): Remove - temporary fix to unblock b/352290057 117 // In robolectric tests the viewer config file isn't current available, so we 118 // cannot use the ProcessedPerfettoProtoLogImpl. 119 Log.e(LOG_TAG, "Failed to find viewer config file " + sViewerConfigPath 120 + " when setting up " + ProtoLogImpl.class.getSimpleName() + ". " 121 + "ProtoLog will not work here!"); 122 123 sServiceInstance = new NoViewerConfigProtoLogImpl(); 124 } else { 125 var datasource = ProtoLog.getSharedSingleInstanceDataSource(); 126 try { 127 var processedProtoLogImpl = 128 new ProcessedPerfettoProtoLogImpl(datasource, sViewerConfigPath, 129 sCacheUpdater, groups); 130 sServiceInstance = processedProtoLogImpl; 131 processedProtoLogImpl.enable(); 132 } catch (ServiceManager.ServiceNotFoundException e) { 133 throw new RuntimeException(e); 134 } 135 } 136 } else { 137 sServiceInstance = createLegacyProtoLogImpl(groups); 138 } 139 140 sCacheUpdater.update(sServiceInstance); 141 } 142 return sServiceInstance; 143 } 144 createLegacyProtoLogImpl(IProtoLogGroup[] groups)145 private static LegacyProtoLogImpl createLegacyProtoLogImpl(IProtoLogGroup[] groups) { 146 var protologImpl = new LegacyProtoLogImpl( 147 sLegacyOutputFilePath, sLegacyViewerConfigPath, sCacheUpdater); 148 protologImpl.registerGroups(groups); 149 150 return protologImpl; 151 } 152 153 @VisibleForTesting setSingleInstance(@ullable IProtoLog instance)154 public static synchronized void setSingleInstance(@Nullable IProtoLog instance) { 155 sServiceInstance = instance; 156 } 157 } 158 159