blob: 59b5a680a2ecffcc18e4226fd2dfcd2a862e305b [file] [log] [blame]
Max Dashoukff9ffbc2021-02-16 11:36:39 -08001/*
2 * Copyright (C) 2021 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 */
16package com.android.car.telemetry;
17
Rui Qiu8c415de2021-05-03 15:52:16 -070018import static android.car.telemetry.CarTelemetryManager.ERROR_NEWER_MANIFEST_EXISTS;
Rui Qiu9bc1bb92021-04-08 15:41:48 -070019import static android.car.telemetry.CarTelemetryManager.ERROR_NONE;
Rui Qiu8c415de2021-05-03 15:52:16 -070020import static android.car.telemetry.CarTelemetryManager.ERROR_PARSE_MANIFEST_FAILED;
21import static android.car.telemetry.CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS;
Rui Qiu9bc1bb92021-04-08 15:41:48 -070022
Rui Qiuf6668202021-04-08 15:37:20 -070023import android.annotation.NonNull;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070024import android.app.StatsManager;
Rui Qiuf6668202021-04-08 15:37:20 -070025import android.car.Car;
Rui Qiu9bc1bb92021-04-08 15:41:48 -070026import android.car.telemetry.CarTelemetryManager.AddManifestError;
Rui Qiuf6668202021-04-08 15:37:20 -070027import android.car.telemetry.ICarTelemetryService;
28import android.car.telemetry.ICarTelemetryServiceListener;
Rui Qiu9bc1bb92021-04-08 15:41:48 -070029import android.car.telemetry.ManifestKey;
Rui Qiuf6668202021-04-08 15:37:20 -070030import android.content.Context;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070031import android.content.SharedPreferences;
Rui Qiua3418982021-08-20 11:21:12 -070032import android.os.Handler;
33import android.os.HandlerThread;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080034import android.util.IndentingPrintWriter;
Rui Qiuf6668202021-04-08 15:37:20 -070035import android.util.Slog;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080036
Rui Qiua3418982021-08-20 11:21:12 -070037import com.android.car.CarLocalServices;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070038import com.android.car.CarPropertyService;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080039import com.android.car.CarServiceBase;
Rui Qiua3418982021-08-20 11:21:12 -070040import com.android.car.CarServiceUtils;
41import com.android.car.systeminterface.SystemInterface;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070042import com.android.car.telemetry.databroker.DataBroker;
43import com.android.car.telemetry.databroker.DataBrokerController;
44import com.android.car.telemetry.databroker.DataBrokerImpl;
45import com.android.car.telemetry.publisher.PublisherFactory;
46import com.android.car.telemetry.publisher.StatsManagerImpl;
47import com.android.car.telemetry.publisher.StatsManagerProxy;
48import com.android.car.telemetry.systemmonitor.SystemMonitor;
Rui Qiuebfbcfb2021-05-18 17:01:27 -070049import com.android.internal.annotations.GuardedBy;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080050
Rui Qiu8c415de2021-05-03 15:52:16 -070051import com.google.protobuf.InvalidProtocolBufferException;
52
Rui Qiua3418982021-08-20 11:21:12 -070053import java.io.File;
Rui Qiu8c415de2021-05-03 15:52:16 -070054import java.util.HashMap;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070055import java.util.List;
Rui Qiu8c415de2021-05-03 15:52:16 -070056import java.util.Map;
57
Max Dashoukff9ffbc2021-02-16 11:36:39 -080058/**
59 * CarTelemetryService manages OEM telemetry collection, processing and communication
60 * with a data upload service.
61 */
Rui Qiuf6668202021-04-08 15:37:20 -070062public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
Max Dashoukff9ffbc2021-02-16 11:36:39 -080063
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -070064 // TODO(b/189340793): Rename Manifest to MetricsConfig
65
Rui Qiuf6668202021-04-08 15:37:20 -070066 private static final boolean DEBUG = false;
Rui Qiu8c415de2021-05-03 15:52:16 -070067 private static final int DEFAULT_VERSION = 0;
Rui Qiuf6668202021-04-08 15:37:20 -070068 private static final String TAG = CarTelemetryService.class.getSimpleName();
Rui Qiua3418982021-08-20 11:21:12 -070069 public static final String TELEMETRY_DIR = "telemetry";
Rui Qiuf6668202021-04-08 15:37:20 -070070
71 private final Context mContext;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070072 private final CarPropertyService mCarPropertyService;
Rui Qiua3418982021-08-20 11:21:12 -070073 private final File mRootDirectory;
74 private final HandlerThread mTelemetryThread = CarServiceUtils.getHandlerThread(
75 CarTelemetryService.class.getSimpleName());
76 private final Handler mTelemetryHandler = new Handler(mTelemetryThread.getLooper());
Rui Qiuebfbcfb2021-05-18 17:01:27 -070077 @GuardedBy("mLock")
Rui Qiu8c415de2021-05-03 15:52:16 -070078 private final Map<String, Integer> mNameVersionMap = new HashMap<>();
Rui Qiuebfbcfb2021-05-18 17:01:27 -070079 private final Object mLock = new Object();
Rui Qiuf6668202021-04-08 15:37:20 -070080
Rui Qiuebfbcfb2021-05-18 17:01:27 -070081 @GuardedBy("mLock")
Rui Qiuf6668202021-04-08 15:37:20 -070082 private ICarTelemetryServiceListener mListener;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070083 private DataBroker mDataBroker;
84 private DataBrokerController mDataBrokerController;
Rui Qiua3418982021-08-20 11:21:12 -070085 private MetricsConfigStore mMetricsConfigStore;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070086 private PublisherFactory mPublisherFactory;
87 private ResultStore mResultStore;
88 private SharedPreferences mSharedPrefs;
89 private StatsManagerProxy mStatsManagerProxy;
90 private SystemMonitor mSystemMonitor;
Rui Qiuf6668202021-04-08 15:37:20 -070091
Rui Qiuac8b5ba2021-08-25 16:04:17 -070092 public CarTelemetryService(Context context, CarPropertyService carPropertyService) {
Rui Qiuf6668202021-04-08 15:37:20 -070093 mContext = context;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070094 mCarPropertyService = carPropertyService;
Rui Qiua3418982021-08-20 11:21:12 -070095 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class);
96 // full root directory path is /data/system/car/telemetry
97 mRootDirectory = new File(systemInterface.getSystemCarDir(), TELEMETRY_DIR);
Max Dashoukff9ffbc2021-02-16 11:36:39 -080098 }
99
100 @Override
101 public void init() {
Rui Qiua3418982021-08-20 11:21:12 -0700102 mTelemetryHandler.post(() -> {
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700103 // initialize all necessary components
Rui Qiua3418982021-08-20 11:21:12 -0700104 mMetricsConfigStore = new MetricsConfigStore(mRootDirectory);
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700105 mResultStore = new ResultStore(mRootDirectory);
106 mStatsManagerProxy = new StatsManagerImpl(
107 mContext.getSystemService(StatsManager.class));
108 // TODO(b/197968695): delay initialization of stats publisher
109 mPublisherFactory = new PublisherFactory(mCarPropertyService, mTelemetryHandler,
110 mStatsManagerProxy, null);
111 mDataBroker = new DataBrokerImpl(mContext, mPublisherFactory, mResultStore);
112 mSystemMonitor = SystemMonitor.create(mContext, mTelemetryHandler);
113 mDataBrokerController = new DataBrokerController(mDataBroker, mSystemMonitor);
114
115 // start collecting data. once data is sent by publisher, scripts will be able to run
116 List<TelemetryProto.MetricsConfig> activeConfigs =
117 mMetricsConfigStore.getActiveMetricsConfigs();
118 for (TelemetryProto.MetricsConfig config : activeConfigs) {
119 mDataBroker.addMetricsConfiguration(config);
120 }
Rui Qiua3418982021-08-20 11:21:12 -0700121 });
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800122 }
123
124 @Override
125 public void release() {
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700126 // TODO(b/197969149): prevent threading issue, block main thread
127 mTelemetryHandler.post(() -> mResultStore.flushToDisk());
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800128 }
129
130 @Override
131 public void dump(IndentingPrintWriter writer) {
132 writer.println("Car Telemetry service");
133 }
Rui Qiuf6668202021-04-08 15:37:20 -0700134
135 /**
136 * Registers a listener with CarTelemetryService for the service to send data to cloud app.
137 */
138 @Override
139 public void setListener(@NonNull ICarTelemetryServiceListener listener) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700140 // TODO(b/184890506): verify that only a hardcoded app can set the listener
Rui Qiuf6668202021-04-08 15:37:20 -0700141 mContext.enforceCallingOrSelfPermission(
142 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700143 synchronized (mLock) {
144 setListenerLocked(listener);
Rui Qiuf6668202021-04-08 15:37:20 -0700145 }
Rui Qiuf6668202021-04-08 15:37:20 -0700146 }
147
148 /**
149 * Clears the listener registered with CarTelemetryService.
150 */
151 @Override
152 public void clearListener() {
153 mContext.enforceCallingOrSelfPermission(
154 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700155 synchronized (mLock) {
156 clearListenerLocked();
Rui Qiuf6668202021-04-08 15:37:20 -0700157 }
Rui Qiuf6668202021-04-08 15:37:20 -0700158 }
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700159
160 /**
161 * Allows client to send telemetry manifests.
162 *
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700163 * @param key the unique key to identify the manifest.
164 * @param config the serialized bytes of a Manifest object.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700165 * @return {@link AddManifestError} the error code.
166 */
167 @Override
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700168 public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] config) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700169 mContext.enforceCallingOrSelfPermission(
170 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700171 synchronized (mLock) {
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700172 return addManifestLocked(key, config);
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700173 }
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700174 }
175
176 /**
177 * Removes a manifest based on the key.
178 */
179 @Override
180 public boolean removeManifest(@NonNull ManifestKey key) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700181 mContext.enforceCallingOrSelfPermission(
182 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700183 synchronized (mLock) {
184 return removeManifestLocked(key);
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700185 }
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700186 }
187
188 /**
189 * Removes all manifests.
190 */
191 @Override
192 public void removeAllManifests() {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700193 mContext.enforceCallingOrSelfPermission(
194 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700195 synchronized (mLock) {
196 removeAllManifestsLocked();
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700197 }
198 }
199
200 /**
201 * Sends script results associated with the given key using the
202 * {@link ICarTelemetryServiceListener}.
203 */
204 @Override
205 public void sendFinishedReports(@NonNull ManifestKey key) {
206 // TODO(b/184087869): Implement
207 mContext.enforceCallingOrSelfPermission(
208 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
209 if (DEBUG) {
210 Slog.d(TAG, "Flushing reports for a manifest");
211 }
212 }
213
214 /**
215 * Sends all script results associated using the {@link ICarTelemetryServiceListener}.
216 */
217 @Override
218 public void sendAllFinishedReports() {
219 // TODO(b/184087869): Implement
220 mContext.enforceCallingOrSelfPermission(
221 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
222 if (DEBUG) {
223 Slog.d(TAG, "Flushing all reports");
224 }
225 }
226
227 /**
228 * Sends all errors using the {@link ICarTelemetryServiceListener}.
229 */
230 @Override
231 public void sendScriptExecutionErrors() {
232 // TODO(b/184087869): Implement
233 mContext.enforceCallingOrSelfPermission(
234 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
235 if (DEBUG) {
236 Slog.d(TAG, "Flushing script execution errors");
237 }
238 }
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700239
240 @GuardedBy("mLock")
241 private void setListenerLocked(@NonNull ICarTelemetryServiceListener listener) {
242 if (DEBUG) {
243 Slog.d(TAG, "Setting the listener for car telemetry service");
244 }
245 mListener = listener;
246 }
247
248 @GuardedBy("mLock")
249 private void clearListenerLocked() {
250 if (DEBUG) {
251 Slog.d(TAG, "Clearing listener");
252 }
253 mListener = null;
254 }
255
256 @GuardedBy("mLock")
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700257 private @AddManifestError int addManifestLocked(ManifestKey key, byte[] configProto) {
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700258 if (DEBUG) {
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700259 Slog.d(TAG, "Adding MetricsConfig to car telemetry service");
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700260 }
261 int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
262 if (currentVersion > key.getVersion()) {
263 return ERROR_NEWER_MANIFEST_EXISTS;
264 } else if (currentVersion == key.getVersion()) {
265 return ERROR_SAME_MANIFEST_EXISTS;
266 }
267
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700268 TelemetryProto.MetricsConfig metricsConfig;
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700269 try {
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700270 metricsConfig = TelemetryProto.MetricsConfig.parseFrom(configProto);
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700271 } catch (InvalidProtocolBufferException e) {
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700272 Slog.e(TAG, "Failed to parse MetricsConfig.", e);
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700273 return ERROR_PARSE_MANIFEST_FAILED;
274 }
275 mNameVersionMap.put(key.getName(), key.getVersion());
276
Zhomart Mukhamejanovee8c0de2021-05-20 11:42:19 -0700277 // TODO(b/186047142): Store the MetricsConfig to disk
278 // TODO(b/186047142): Send metricsConfig to a script manager or a queue
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700279 return ERROR_NONE;
280 }
281
282 @GuardedBy("mLock")
283 private boolean removeManifestLocked(@NonNull ManifestKey key) {
284 Integer version = mNameVersionMap.remove(key.getName());
285 if (version == null) {
286 return false;
287 }
288 // TODO(b/186047142): Delete manifest from disk and remove it from queue
289 return true;
290 }
291
292 @GuardedBy("mLock")
293 private void removeAllManifestsLocked() {
294 if (DEBUG) {
295 Slog.d(TAG, "Removing all manifest from car telemetry service");
296 }
297 mNameVersionMap.clear();
298 // TODO(b/186047142): Delete all manifests from disk & queue
299 }
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800300}