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 com.android.internal.protolog.common.ILogger;
20 
21 import org.json.JSONException;
22 import org.json.JSONObject;
23 
24 import java.io.BufferedReader;
25 import java.io.FileInputStream;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.util.Iterator;
31 import java.util.Map;
32 import java.util.TreeMap;
33 import java.util.zip.GZIPInputStream;
34 
35 /**
36  * Handles loading and parsing of ProtoLog viewer configuration.
37  */
38 public class LegacyProtoLogViewerConfigReader {
39 
40     private static final String TAG = "ProtoLogViewerConfigReader";
41     private Map<Long, String> mLogMessageMap = null;
42 
43     /** Returns message format string for its hash or null if unavailable. */
getViewerString(long messageHash)44     public synchronized String getViewerString(long messageHash) {
45         if (mLogMessageMap != null) {
46             return mLogMessageMap.get(messageHash);
47         } else {
48             return null;
49         }
50     }
51 
52     /**
53      * Reads the specified viewer configuration file. Does nothing if the config is already loaded.
54      */
loadViewerConfig(ILogger logger, String viewerConfigFilename)55     public synchronized void loadViewerConfig(ILogger logger, String viewerConfigFilename) {
56         try {
57             loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
58             logger.log("Loaded " + mLogMessageMap.size()
59                     + " log definitions from " + viewerConfigFilename);
60         } catch (FileNotFoundException e) {
61             logger.log("Unable to load log definitions: File "
62                     + viewerConfigFilename + " not found." + e);
63         } catch (IOException e) {
64             logger.log("Unable to load log definitions: IOException while reading "
65                     + viewerConfigFilename + ". " + e);
66         } catch (JSONException e) {
67             logger.log("Unable to load log definitions: JSON parsing exception while reading "
68                     + viewerConfigFilename + ". " + e);
69         }
70     }
71 
72     /**
73      * Reads the specified viewer configuration input stream.
74      * Does nothing if the config is already loaded.
75      */
loadViewerConfig(InputStream viewerConfigInputStream)76     public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
77             throws IOException, JSONException {
78         if (mLogMessageMap != null) {
79             return;
80         }
81         InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
82         BufferedReader reader = new BufferedReader(config);
83         StringBuilder builder = new StringBuilder();
84         String line;
85         while ((line = reader.readLine()) != null) {
86             builder.append(line).append('\n');
87         }
88         reader.close();
89         JSONObject json = new JSONObject(builder.toString());
90         JSONObject messages = json.getJSONObject("messages");
91 
92         mLogMessageMap = new TreeMap<>();
93         Iterator it = messages.keys();
94         while (it.hasNext()) {
95             String key = (String) it.next();
96             try {
97                 long hash = Long.parseLong(key);
98                 JSONObject val = messages.getJSONObject(key);
99                 String msg = val.getString("message");
100                 mLogMessageMap.put(hash, msg);
101             } catch (NumberFormatException expected) {
102                 // Not a messageHash - skip it
103             }
104         }
105     }
106 
107     /**
108      * Returns the number of loaded log definitions kept in memory.
109      */
knownViewerStringsNumber()110     public synchronized int knownViewerStringsNumber() {
111         if (mLogMessageMap != null) {
112             return mLogMessageMap.size();
113         }
114         return 0;
115     }
116 
117 }
118