• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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