1 package android.car.vms; 2 3 import android.annotation.SystemApi; 4 import android.util.Log; 5 6 import com.android.internal.annotations.VisibleForTesting; 7 8 import org.json.JSONArray; 9 import org.json.JSONException; 10 import org.json.JSONObject; 11 12 /** 13 * Records VMS operations using the Android Log. 14 * 15 * This class records VMS operations. The recorded messages include the VMS operations and its 16 * arguments encoded as JSON text so that the string can be both read as a log message and easily 17 * parsed. VmsOperationRecorder is intended to be called after successful state change. 18 * 19 * Access the VmsOperationRecorder using the {@link #get()} method, which returns a singleton 20 * instance. Each VMS operation has a corresponding VmsOperationRecorder method. For instance: 21 * <pre>{@code 22 * VmsOperationRecorder.get().subscribe(layer); 23 * }</pre> 24 * 25 * @hide 26 */ 27 @SystemApi 28 public final class VmsOperationRecorder { 29 private static final String TAG = "VmsOperationRecorder"; 30 private static final VmsOperationRecorder INSTANCE = new VmsOperationRecorder(new Writer()); 31 private final Writer mWriter; 32 33 @VisibleForTesting VmsOperationRecorder(Writer writer)34 public VmsOperationRecorder(Writer writer) { 35 mWriter = writer; 36 } 37 38 /** Return the singleton instance. */ get()39 public static VmsOperationRecorder get() { 40 return INSTANCE; 41 } 42 43 // VMS Client operations. 44 subscribe(VmsLayer layer)45 public void subscribe(VmsLayer layer) { 46 recordOp("subscribe", layer); 47 } 48 unsubscribe(VmsLayer layer)49 public void unsubscribe(VmsLayer layer) { 50 recordOp("unsubscribe", layer); 51 } 52 subscribe(VmsLayer layer, int publisherId)53 public void subscribe(VmsLayer layer, int publisherId) { 54 recordOp("subscribe", "publisherId", publisherId, layer); 55 } 56 unsubscribe(VmsLayer layer, int publisherId)57 public void unsubscribe(VmsLayer layer, int publisherId) { 58 recordOp("unsubscribe", "publisherId", publisherId, layer); 59 } 60 startMonitoring()61 public void startMonitoring() { 62 recordOp("startMonitoring"); 63 } 64 stopMonitoring()65 public void stopMonitoring() { 66 recordOp("stopMonitoring"); 67 } 68 setLayersOffering(VmsLayersOffering layersOffering)69 public void setLayersOffering(VmsLayersOffering layersOffering) { 70 recordOp("setLayersOffering", layersOffering); 71 } 72 getPublisherId(int publisherId)73 public void getPublisherId(int publisherId) { 74 recordOp("getPublisherId", "publisherId", publisherId); 75 } 76 77 // VMS Service operations. 78 addSubscription(int sequenceNumber, VmsLayer layer)79 public void addSubscription(int sequenceNumber, VmsLayer layer) { 80 recordOp("addSubscription", "sequenceNumber", sequenceNumber, layer); 81 } 82 removeSubscription(int sequenceNumber, VmsLayer layer)83 public void removeSubscription(int sequenceNumber, VmsLayer layer) { 84 recordOp("removeSubscription", "sequenceNumber", sequenceNumber, layer); 85 } 86 addPromiscuousSubscription(int sequenceNumber)87 public void addPromiscuousSubscription(int sequenceNumber) { 88 recordOp("addPromiscuousSubscription", "sequenceNumber", sequenceNumber); 89 } 90 removePromiscuousSubscription(int sequenceNumber)91 public void removePromiscuousSubscription(int sequenceNumber) { 92 recordOp("removePromiscuousSubscription", "sequenceNumber", sequenceNumber); 93 } 94 addHalSubscription(int sequenceNumber, VmsLayer layer)95 public void addHalSubscription(int sequenceNumber, VmsLayer layer) { 96 recordOp("addHalSubscription", "sequenceNumber", sequenceNumber, layer); 97 } 98 removeHalSubscription(int sequenceNumber, VmsLayer layer)99 public void removeHalSubscription(int sequenceNumber, VmsLayer layer) { 100 recordOp("removeHalSubscription", "sequenceNumber", sequenceNumber, layer); 101 } 102 setPublisherLayersOffering(VmsLayersOffering layersOffering)103 public void setPublisherLayersOffering(VmsLayersOffering layersOffering) { 104 recordOp("setPublisherLayersOffering", layersOffering); 105 } 106 setHalPublisherLayersOffering(VmsLayersOffering layersOffering)107 public void setHalPublisherLayersOffering(VmsLayersOffering layersOffering) { 108 recordOp("setHalPublisherLayersOffering", layersOffering); 109 } 110 recordOp(String operation)111 private void recordOp(String operation) { 112 if (isEnabled()) { 113 try { 114 write(new JSONObject().put(operation, new JSONObject())); 115 } catch (JSONException e) { 116 Log.e(TAG, e.toString()); 117 } 118 } 119 } 120 recordOp(String operation, VmsLayer layer)121 private void recordOp(String operation, VmsLayer layer) { 122 if (isEnabled()) { 123 try { 124 recordOp(operation, new JSONObject().put("layer", toJson(layer))); 125 } catch (JSONException e) { 126 Log.e(TAG, e.toString()); 127 } 128 } 129 } 130 recordOp(String operation, VmsLayersOffering layersOffering)131 private void recordOp(String operation, VmsLayersOffering layersOffering) { 132 if (isEnabled()) { 133 try { 134 JSONObject args = new JSONObject(); 135 JSONArray offering = toJson(layersOffering); 136 if (offering.length() > 0) { 137 args.put("layerDependency", offering); 138 } 139 recordOp(operation, args); 140 } catch (JSONException e) { 141 Log.e(TAG, e.toString()); 142 } 143 } 144 } 145 recordOp(String operation, String intArgName, int arg)146 private void recordOp(String operation, String intArgName, int arg) { 147 if (isEnabled()) { 148 try { 149 recordOp(operation, new JSONObject().put(intArgName, arg)); 150 } catch (JSONException e) { 151 Log.e(TAG, e.toString()); 152 } 153 } 154 } 155 recordOp(String operation, String intArgName, int arg, VmsLayer layer)156 private void recordOp(String operation, String intArgName, int arg, VmsLayer layer) { 157 if (isEnabled()) { 158 try { 159 recordOp(operation, 160 new JSONObject().put(intArgName, arg).put("layer", toJson(layer))); 161 } catch (JSONException e) { 162 Log.e(TAG, e.toString()); 163 } 164 } 165 } 166 recordOp(String operation, JSONObject args)167 private void recordOp(String operation, JSONObject args) { 168 if (isEnabled()) { 169 try { 170 write(new JSONObject().put(operation, args)); 171 } catch (JSONException e) { 172 Log.e(TAG, e.toString()); 173 } 174 } 175 } 176 toJson(VmsLayer layer)177 private static JSONObject toJson(VmsLayer layer) throws JSONException { 178 return new JSONObject() 179 .put("type", layer.getType()) 180 .put("subtype", layer.getSubtype()) 181 .put("version", layer.getVersion()); 182 } 183 toJson(VmsLayerDependency layerDependency)184 private static JSONObject toJson(VmsLayerDependency layerDependency) throws JSONException { 185 JSONObject dep = new JSONObject(); 186 dep.put("layer", toJson(layerDependency.getLayer())); 187 if (!layerDependency.getDependencies().isEmpty()) { 188 JSONArray dependencies = new JSONArray(); 189 for (VmsLayer dependency : layerDependency.getDependencies()) { 190 dependencies.put(toJson(dependency)); 191 } 192 dep.put("dependency", dependencies); 193 } 194 return dep; 195 } 196 toJson(VmsLayersOffering layersOffering)197 private static JSONArray toJson(VmsLayersOffering layersOffering) throws JSONException { 198 JSONArray offerings = new JSONArray(); 199 for (VmsLayerDependency layerDependency : layersOffering.getDependencies()) { 200 offerings.put(toJson(layerDependency)); 201 } 202 return offerings; 203 } 204 isEnabled()205 private boolean isEnabled() { 206 return mWriter.isEnabled(); 207 } 208 write(JSONObject object)209 private void write(JSONObject object) { 210 mWriter.write(object.toString()); 211 } 212 213 /** @hide */ 214 @VisibleForTesting 215 public static class Writer { 216 private static final String TAG = "VMS.RECORD.EVENT"; 217 private static final int LEVEL = Log.DEBUG; 218 isEnabled()219 public boolean isEnabled() { 220 return Log.isLoggable(TAG, LEVEL); 221 } 222 write(String msg)223 public void write(String msg) { 224 Log.println(LEVEL, TAG, msg); 225 } 226 } 227 } 228