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 /** @hide */ 34 @VisibleForTesting VmsOperationRecorder(Writer writer)35 public VmsOperationRecorder(Writer writer) { 36 mWriter = writer; 37 } 38 39 /** Return the singleton instance. */ get()40 public static VmsOperationRecorder get() { 41 return INSTANCE; 42 } 43 44 // VMS Client operations. 45 subscribe(VmsLayer layer)46 public void subscribe(VmsLayer layer) { 47 recordOp("subscribe", layer); 48 } 49 unsubscribe(VmsLayer layer)50 public void unsubscribe(VmsLayer layer) { 51 recordOp("unsubscribe", layer); 52 } 53 subscribe(VmsLayer layer, int publisherId)54 public void subscribe(VmsLayer layer, int publisherId) { 55 recordOp("subscribe", "publisherId", publisherId, layer); 56 } 57 unsubscribe(VmsLayer layer, int publisherId)58 public void unsubscribe(VmsLayer layer, int publisherId) { 59 recordOp("unsubscribe", "publisherId", publisherId, layer); 60 } 61 startMonitoring()62 public void startMonitoring() { 63 recordOp("startMonitoring"); 64 } 65 stopMonitoring()66 public void stopMonitoring() { 67 recordOp("stopMonitoring"); 68 } 69 setLayersOffering(VmsLayersOffering layersOffering)70 public void setLayersOffering(VmsLayersOffering layersOffering) { 71 recordOp("setLayersOffering", layersOffering); 72 } 73 getPublisherId(int publisherId)74 public void getPublisherId(int publisherId) { 75 recordOp("getPublisherId", "publisherId", publisherId); 76 } 77 78 // VMS Service operations. 79 addSubscription(int sequenceNumber, VmsLayer layer)80 public void addSubscription(int sequenceNumber, VmsLayer layer) { 81 recordOp("addSubscription", "sequenceNumber", sequenceNumber, layer); 82 } 83 removeSubscription(int sequenceNumber, VmsLayer layer)84 public void removeSubscription(int sequenceNumber, VmsLayer layer) { 85 recordOp("removeSubscription", "sequenceNumber", sequenceNumber, layer); 86 } 87 addPromiscuousSubscription(int sequenceNumber)88 public void addPromiscuousSubscription(int sequenceNumber) { 89 recordOp("addPromiscuousSubscription", "sequenceNumber", sequenceNumber); 90 } 91 removePromiscuousSubscription(int sequenceNumber)92 public void removePromiscuousSubscription(int sequenceNumber) { 93 recordOp("removePromiscuousSubscription", "sequenceNumber", sequenceNumber); 94 } 95 addHalSubscription(int sequenceNumber, VmsLayer layer)96 public void addHalSubscription(int sequenceNumber, VmsLayer layer) { 97 recordOp("addHalSubscription", "sequenceNumber", sequenceNumber, layer); 98 } 99 removeHalSubscription(int sequenceNumber, VmsLayer layer)100 public void removeHalSubscription(int sequenceNumber, VmsLayer layer) { 101 recordOp("removeHalSubscription", "sequenceNumber", sequenceNumber, layer); 102 } 103 setPublisherLayersOffering(VmsLayersOffering layersOffering)104 public void setPublisherLayersOffering(VmsLayersOffering layersOffering) { 105 recordOp("setPublisherLayersOffering", layersOffering); 106 } 107 setHalPublisherLayersOffering(VmsLayersOffering layersOffering)108 public void setHalPublisherLayersOffering(VmsLayersOffering layersOffering) { 109 recordOp("setHalPublisherLayersOffering", layersOffering); 110 } 111 recordOp(String operation)112 private void recordOp(String operation) { 113 if (isEnabled()) { 114 try { 115 write(new JSONObject().put(operation, new JSONObject())); 116 } catch (JSONException e) { 117 Log.e(TAG, e.toString()); 118 } 119 } 120 } 121 recordOp(String operation, VmsLayer layer)122 private void recordOp(String operation, VmsLayer layer) { 123 if (isEnabled()) { 124 try { 125 recordOp(operation, new JSONObject().put("layer", toJson(layer))); 126 } catch (JSONException e) { 127 Log.e(TAG, e.toString()); 128 } 129 } 130 } 131 recordOp(String operation, VmsLayersOffering layersOffering)132 private void recordOp(String operation, VmsLayersOffering layersOffering) { 133 if (isEnabled()) { 134 try { 135 JSONObject args = new JSONObject(); 136 args.put("publisherId", layersOffering.getPublisherId()); 137 JSONArray offering = toJson(layersOffering); 138 if (offering.length() > 0) { 139 args.put("layerDependency", offering); 140 } 141 recordOp(operation, args); 142 } catch (JSONException e) { 143 Log.e(TAG, e.toString()); 144 } 145 } 146 } 147 recordOp(String operation, String intArgName, int arg)148 private void recordOp(String operation, String intArgName, int arg) { 149 if (isEnabled()) { 150 try { 151 recordOp(operation, new JSONObject().put(intArgName, arg)); 152 } catch (JSONException e) { 153 Log.e(TAG, e.toString()); 154 } 155 } 156 } 157 recordOp(String operation, String intArgName, int arg, VmsLayer layer)158 private void recordOp(String operation, String intArgName, int arg, VmsLayer layer) { 159 if (isEnabled()) { 160 try { 161 recordOp(operation, 162 new JSONObject().put(intArgName, arg).put("layer", toJson(layer))); 163 } catch (JSONException e) { 164 Log.e(TAG, e.toString()); 165 } 166 } 167 } 168 recordOp(String operation, JSONObject args)169 private void recordOp(String operation, JSONObject args) { 170 if (isEnabled()) { 171 try { 172 write(new JSONObject().put(operation, args)); 173 } catch (JSONException e) { 174 Log.e(TAG, e.toString()); 175 } 176 } 177 } 178 toJson(VmsLayer layer)179 private static JSONObject toJson(VmsLayer layer) throws JSONException { 180 return new JSONObject() 181 .put("type", layer.getType()) 182 .put("subtype", layer.getSubtype()) 183 .put("version", layer.getVersion()); 184 } 185 toJson(VmsLayerDependency layerDependency)186 private static JSONObject toJson(VmsLayerDependency layerDependency) throws JSONException { 187 JSONObject dep = new JSONObject(); 188 dep.put("layer", toJson(layerDependency.getLayer())); 189 if (!layerDependency.getDependencies().isEmpty()) { 190 JSONArray dependencies = new JSONArray(); 191 for (VmsLayer dependency : layerDependency.getDependencies()) { 192 dependencies.put(toJson(dependency)); 193 } 194 dep.put("dependency", dependencies); 195 } 196 return dep; 197 } 198 toJson(VmsLayersOffering layersOffering)199 private static JSONArray toJson(VmsLayersOffering layersOffering) throws JSONException { 200 JSONArray offerings = new JSONArray(); 201 for (VmsLayerDependency layerDependency : layersOffering.getDependencies()) { 202 offerings.put(toJson(layerDependency)); 203 } 204 return offerings; 205 } 206 isEnabled()207 private boolean isEnabled() { 208 return mWriter.isEnabled(); 209 } 210 write(JSONObject object)211 private void write(JSONObject object) { 212 mWriter.write(object.toString()); 213 } 214 215 /** @hide */ 216 @VisibleForTesting 217 public static class Writer { 218 private static final String TAG = "VMS.RECORD.EVENT"; 219 private static final int LEVEL = Log.DEBUG; 220 isEnabled()221 public boolean isEnabled() { 222 return Log.isLoggable(TAG, LEVEL); 223 } 224 write(String msg)225 public void write(String msg) { 226 Log.println(LEVEL, TAG, msg); 227 } 228 } 229 } 230