1 /*
2  * Copyright (C) 2017 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 android.car.vms;
18 
19 import android.annotation.SystemApi;
20 import android.util.Log;
21 import android.util.Slog;
22 
23 import com.android.internal.annotations.VisibleForTesting;
24 
25 import org.json.JSONArray;
26 import org.json.JSONException;
27 import org.json.JSONObject;
28 
29 /**
30  * Records VMS operations using the Android Log.
31  *
32  * This class records VMS operations. The recorded messages include the VMS operations and its
33  * arguments encoded as JSON text so that the string can be both read as a log message and easily
34  * parsed. VmsOperationRecorder is intended to be called after successful state change.
35  *
36  * Access the VmsOperationRecorder using the {@link #get()} method, which returns a singleton
37  * instance. Each VMS operation has a corresponding VmsOperationRecorder method. For instance:
38  * <pre>{@code
39  *   VmsOperationRecorder.get().subscribe(layer);
40  * }</pre>
41  *
42  * @deprecated VmsOperationRecorder is no longer used by VMS and will produce no output
43  * @hide
44  */
45 @Deprecated
46 @SystemApi
47 public final class VmsOperationRecorder {
48     private static final String TAG = "VmsOperationRecorder";
49     private static final VmsOperationRecorder INSTANCE = new VmsOperationRecorder(new Writer());
50     private final Writer mWriter;
51 
52     /** @hide */
53     @VisibleForTesting
VmsOperationRecorder(Writer writer)54     public VmsOperationRecorder(Writer writer) {
55         mWriter = writer;
56     }
57 
58     /** Return the singleton instance. */
get()59     public static VmsOperationRecorder get() {
60         return INSTANCE;
61     }
62 
63     // VMS Client operations.
64 
65     /**
66      * Records {@code subscribe} operation with the {@link VmsLayer} layer passed as parameter.
67      */
subscribe(VmsLayer layer)68     public void subscribe(VmsLayer layer) {
69         recordOp("subscribe", layer);
70     }
71 
72     /**
73      * Records {@code unsubscribe} operation with the {@link VmsLayer} layer passed as parameter.
74      */
unsubscribe(VmsLayer layer)75     public void unsubscribe(VmsLayer layer) {
76         recordOp("unsubscribe", layer);
77     }
78 
79     /**
80      * Records {@code subscribe} operation with the {@link VmsLayer} layer and publisher id passed
81      * both as parameter.
82      */
subscribe(VmsLayer layer, int publisherId)83     public void subscribe(VmsLayer layer, int publisherId) {
84         recordOp("subscribe", "publisherId", publisherId, layer);
85     }
86 
87     /**
88      * Record {@code unsubscribe} operation with the {@link VmsLayer} layer and publisher id passed
89      * both as parameter.
90      */
unsubscribe(VmsLayer layer, int publisherId)91     public void unsubscribe(VmsLayer layer, int publisherId) {
92         recordOp("unsubscribe", "publisherId", publisherId, layer);
93     }
94 
95     /**
96      * Records {@code startMonitoring} operation.
97      */
startMonitoring()98     public void startMonitoring() {
99         recordOp("startMonitoring");
100     }
101 
102     /**
103      * Records {@code stopMonitoring} operation.
104      */
stopMonitoring()105     public void stopMonitoring() {
106         recordOp("stopMonitoring");
107     }
108 
109     /**
110      * Records {@code setLayerOffering} operation with the {@link VmsLayerOffering} offering
111      * passed as parameter.
112      */
setLayersOffering(VmsLayersOffering layersOffering)113     public void setLayersOffering(VmsLayersOffering layersOffering) {
114         recordOp("setLayersOffering", layersOffering);
115     }
116 
117     /**
118      * Records {@code getPublisherId} operation with the publisher id passed as parameter.
119      */
getPublisherId(int publisherId)120     public void getPublisherId(int publisherId) {
121         recordOp("getPublisherId", "publisherId", publisherId);
122     }
123 
124     // VMS Service operations.
125 
126     /**
127      * Records {@code addSubscription} operation with the {@link VmsLayer} and the sequenceNumber
128      * passed as parameter.
129      */
addSubscription(int sequenceNumber, VmsLayer layer)130     public void addSubscription(int sequenceNumber, VmsLayer layer) {
131         recordOp("addSubscription", "sequenceNumber", sequenceNumber, layer);
132     }
133 
134     /**
135      * Records {@code addPromiscuousSubscription} operation with the {@link VmsLayer} and the
136      * sequenceNumber passed as parameter.
137      */
removeSubscription(int sequenceNumber, VmsLayer layer)138     public void removeSubscription(int sequenceNumber, VmsLayer layer) {
139         recordOp("removeSubscription", "sequenceNumber", sequenceNumber, layer);
140     }
141 
142     /**
143      * Records {@code addPromiscuousSubscription} operation with the sequenceNumber passed as
144      * parameter.
145      */
addPromiscuousSubscription(int sequenceNumber)146     public void addPromiscuousSubscription(int sequenceNumber) {
147         recordOp("addPromiscuousSubscription", "sequenceNumber", sequenceNumber);
148     }
149 
150     /**
151      * Records {@code removePromiscuousSubscription} operation with the sequenceNumber passed as
152      * parameter.
153      */
removePromiscuousSubscription(int sequenceNumber)154     public void removePromiscuousSubscription(int sequenceNumber) {
155         recordOp("removePromiscuousSubscription", "sequenceNumber", sequenceNumber);
156     }
157 
158     /**
159      * Records {@code addHalSubscription} operation with the {@link VmsLayer} layer and
160      * sequenceNumber both passed as parameter.
161      */
addHalSubscription(int sequenceNumber, VmsLayer layer)162     public void addHalSubscription(int sequenceNumber, VmsLayer layer) {
163         recordOp("addHalSubscription", "sequenceNumber", sequenceNumber, layer);
164     }
165 
166     /**
167      * Records {@code removeHalSubscription} operation with the {@link VmsLayer} layer and
168      * sequenceNumber both passed as parameter.
169      */
removeHalSubscription(int sequenceNumber, VmsLayer layer)170     public void removeHalSubscription(int sequenceNumber, VmsLayer layer) {
171         recordOp("removeHalSubscription", "sequenceNumber", sequenceNumber, layer);
172     }
173 
174     /**
175      * Records {@code setPublisherLayersOffering} operation with the {@link VmsLayersOffering}
176      * layersOffering passed as parameter.
177      */
setPublisherLayersOffering(VmsLayersOffering layersOffering)178     public void setPublisherLayersOffering(VmsLayersOffering layersOffering) {
179         recordOp("setPublisherLayersOffering", layersOffering);
180     }
181 
182     /**
183      * Records {@code setHalPublisherLayersOffering} operation with the {@link VmsLayersOffering}
184      * layersOffering passed as parameter.
185      */
setHalPublisherLayersOffering(VmsLayersOffering layersOffering)186     public void setHalPublisherLayersOffering(VmsLayersOffering layersOffering) {
187         recordOp("setHalPublisherLayersOffering", layersOffering);
188     }
189 
recordOp(String operation)190     private void recordOp(String operation) {
191         if (isEnabled()) {
192             try {
193                 write(new JSONObject().put(operation, new JSONObject()));
194             } catch (JSONException e) {
195                 Slog.e(TAG, e.toString());
196             }
197         }
198     }
199 
recordOp(String operation, VmsLayer layer)200     private void recordOp(String operation, VmsLayer layer) {
201         if (isEnabled()) {
202             try {
203                 recordOp(operation, new JSONObject().put("layer", toJson(layer)));
204             } catch (JSONException e) {
205                 Slog.e(TAG, e.toString());
206             }
207         }
208     }
209 
recordOp(String operation, VmsLayersOffering layersOffering)210     private void recordOp(String operation, VmsLayersOffering layersOffering) {
211         if (isEnabled()) {
212             try {
213                 JSONObject args = new JSONObject();
214                 args.put("publisherId", layersOffering.getPublisherId());
215                 JSONArray offering = toJson(layersOffering);
216                 if (offering.length() > 0) {
217                     args.put("layerDependency", offering);
218                 }
219                 recordOp(operation, args);
220             } catch (JSONException e) {
221                 Slog.e(TAG, e.toString());
222             }
223         }
224     }
225 
recordOp(String operation, String intArgName, int arg)226     private void recordOp(String operation, String intArgName, int arg) {
227         if (isEnabled()) {
228             try {
229                 recordOp(operation, new JSONObject().put(intArgName, arg));
230             } catch (JSONException e) {
231                 Slog.e(TAG, e.toString());
232             }
233         }
234     }
235 
recordOp(String operation, String intArgName, int arg, VmsLayer layer)236     private void recordOp(String operation, String intArgName, int arg, VmsLayer layer) {
237         if (isEnabled()) {
238             try {
239                 recordOp(operation,
240                         new JSONObject().put(intArgName, arg).put("layer", toJson(layer)));
241             } catch (JSONException e) {
242                 Slog.e(TAG, e.toString());
243             }
244         }
245     }
246 
recordOp(String operation, JSONObject args)247     private void recordOp(String operation, JSONObject args) {
248         if (isEnabled()) {
249             try {
250                 write(new JSONObject().put(operation, args));
251             } catch (JSONException e) {
252                 Slog.e(TAG, e.toString());
253             }
254         }
255     }
256 
toJson(VmsLayer layer)257     private static JSONObject toJson(VmsLayer layer) throws JSONException {
258         return new JSONObject()
259                 .put("type", layer.getType())
260                 .put("subtype", layer.getSubtype())
261                 .put("version", layer.getVersion());
262     }
263 
toJson(VmsLayerDependency layerDependency)264     private static JSONObject toJson(VmsLayerDependency layerDependency) throws JSONException {
265         JSONObject dep = new JSONObject();
266         dep.put("layer", toJson(layerDependency.getLayer()));
267         if (!layerDependency.getDependencies().isEmpty()) {
268             JSONArray dependencies = new JSONArray();
269             for (VmsLayer dependency : layerDependency.getDependencies()) {
270                 dependencies.put(toJson(dependency));
271             }
272             dep.put("dependency", dependencies);
273         }
274         return dep;
275     }
276 
toJson(VmsLayersOffering layersOffering)277     private static JSONArray toJson(VmsLayersOffering layersOffering) throws JSONException {
278         JSONArray offerings = new JSONArray();
279         for (VmsLayerDependency layerDependency : layersOffering.getDependencies()) {
280             offerings.put(toJson(layerDependency));
281         }
282         return offerings;
283     }
284 
isEnabled()285     private boolean isEnabled() {
286         return mWriter.isEnabled();
287     }
288 
write(JSONObject object)289     private void write(JSONObject object) {
290         mWriter.write(object.toString());
291     }
292 
293     /** @hide */
294     @VisibleForTesting
295     public static class Writer {
296         private static final String TAG = "VMS.RECORD.EVENT";
297         private static final int LEVEL = Log.DEBUG;
298 
isEnabled()299         public boolean isEnabled() {
300             return Log.isLoggable(TAG, LEVEL);
301         }
302 
303         /** Logs the message passed as parameter. */
write(String msg)304         public void write(String msg) {
305             Log.println(LEVEL, TAG, msg);
306         }
307     }
308 }
309