blob: 537ce455512ae6f56708c3cd62ddbca1b986c413 [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 Qiuf721b132021-09-10 12:41:09 -070018import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_NONE;
Rui Qiu9b9341c2021-08-25 10:39:04 -070019import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_PARSE_FAILED;
Rui Qiuf721b132021-09-10 12:41:09 -070020import static android.car.telemetry.CarTelemetryManager.ERROR_METRICS_CONFIG_UNKNOWN;
Rui Qiu9bc1bb92021-04-08 15:41:48 -070021
Rui Qiuf6668202021-04-08 15:37:20 -070022import android.annotation.NonNull;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070023import android.app.StatsManager;
Rui Qiuf6668202021-04-08 15:37:20 -070024import android.car.Car;
25import android.car.telemetry.ICarTelemetryService;
26import android.car.telemetry.ICarTelemetryServiceListener;
Rui Qiu9b9341c2021-08-25 10:39:04 -070027import android.car.telemetry.MetricsConfigKey;
Rui Qiuf6668202021-04-08 15:37:20 -070028import android.content.Context;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070029import android.content.SharedPreferences;
Rui Qiua3418982021-08-20 11:21:12 -070030import android.os.Handler;
31import android.os.HandlerThread;
Rui Qiu9b9341c2021-08-25 10:39:04 -070032import android.os.RemoteException;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080033import android.util.IndentingPrintWriter;
Rui Qiuf6668202021-04-08 15:37:20 -070034import android.util.Slog;
Max Dashoukff9ffbc2021-02-16 11:36:39 -080035
Rui Qiua3418982021-08-20 11:21:12 -070036import com.android.car.CarLocalServices;
Rui Qiu9b9341c2021-08-25 10:39:04 -070037import com.android.car.CarLog;
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 Qiu9b9341c2021-08-25 10:39:04 -070049import com.android.internal.annotations.VisibleForTesting;
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 Qiuac8b5ba2021-08-25 16:04:17 -070054import java.util.List;
Rui Qiu8c415de2021-05-03 15:52:16 -070055
Max Dashoukff9ffbc2021-02-16 11:36:39 -080056/**
57 * CarTelemetryService manages OEM telemetry collection, processing and communication
58 * with a data upload service.
59 */
Rui Qiuf6668202021-04-08 15:37:20 -070060public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
Max Dashoukff9ffbc2021-02-16 11:36:39 -080061
Rui Qiuf6668202021-04-08 15:37:20 -070062 private static final boolean DEBUG = false;
Rui Qiua3418982021-08-20 11:21:12 -070063 public static final String TELEMETRY_DIR = "telemetry";
Rui Qiuf6668202021-04-08 15:37:20 -070064
65 private final Context mContext;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070066 private final CarPropertyService mCarPropertyService;
Rui Qiua3418982021-08-20 11:21:12 -070067 private final File mRootDirectory;
68 private final HandlerThread mTelemetryThread = CarServiceUtils.getHandlerThread(
69 CarTelemetryService.class.getSimpleName());
70 private final Handler mTelemetryHandler = new Handler(mTelemetryThread.getLooper());
Rui Qiuf6668202021-04-08 15:37:20 -070071
72 private ICarTelemetryServiceListener mListener;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070073 private DataBroker mDataBroker;
74 private DataBrokerController mDataBrokerController;
Rui Qiua3418982021-08-20 11:21:12 -070075 private MetricsConfigStore mMetricsConfigStore;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070076 private PublisherFactory mPublisherFactory;
77 private ResultStore mResultStore;
78 private SharedPreferences mSharedPrefs;
79 private StatsManagerProxy mStatsManagerProxy;
80 private SystemMonitor mSystemMonitor;
Rui Qiuf6668202021-04-08 15:37:20 -070081
Rui Qiuac8b5ba2021-08-25 16:04:17 -070082 public CarTelemetryService(Context context, CarPropertyService carPropertyService) {
Rui Qiuf6668202021-04-08 15:37:20 -070083 mContext = context;
Rui Qiuac8b5ba2021-08-25 16:04:17 -070084 mCarPropertyService = carPropertyService;
Rui Qiua3418982021-08-20 11:21:12 -070085 SystemInterface systemInterface = CarLocalServices.getService(SystemInterface.class);
86 // full root directory path is /data/system/car/telemetry
87 mRootDirectory = new File(systemInterface.getSystemCarDir(), TELEMETRY_DIR);
Max Dashoukff9ffbc2021-02-16 11:36:39 -080088 }
89
90 @Override
91 public void init() {
Rui Qiua3418982021-08-20 11:21:12 -070092 mTelemetryHandler.post(() -> {
Rui Qiuac8b5ba2021-08-25 16:04:17 -070093 // initialize all necessary components
Rui Qiua3418982021-08-20 11:21:12 -070094 mMetricsConfigStore = new MetricsConfigStore(mRootDirectory);
Rui Qiuac8b5ba2021-08-25 16:04:17 -070095 mResultStore = new ResultStore(mRootDirectory);
96 mStatsManagerProxy = new StatsManagerImpl(
97 mContext.getSystemService(StatsManager.class));
98 // TODO(b/197968695): delay initialization of stats publisher
99 mPublisherFactory = new PublisherFactory(mCarPropertyService, mTelemetryHandler,
100 mStatsManagerProxy, null);
101 mDataBroker = new DataBrokerImpl(mContext, mPublisherFactory, mResultStore);
102 mSystemMonitor = SystemMonitor.create(mContext, mTelemetryHandler);
103 mDataBrokerController = new DataBrokerController(mDataBroker, mSystemMonitor);
104
105 // start collecting data. once data is sent by publisher, scripts will be able to run
106 List<TelemetryProto.MetricsConfig> activeConfigs =
107 mMetricsConfigStore.getActiveMetricsConfigs();
108 for (TelemetryProto.MetricsConfig config : activeConfigs) {
109 mDataBroker.addMetricsConfiguration(config);
110 }
Rui Qiua3418982021-08-20 11:21:12 -0700111 });
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800112 }
113
114 @Override
115 public void release() {
Rui Qiuac8b5ba2021-08-25 16:04:17 -0700116 // TODO(b/197969149): prevent threading issue, block main thread
117 mTelemetryHandler.post(() -> mResultStore.flushToDisk());
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800118 }
119
120 @Override
121 public void dump(IndentingPrintWriter writer) {
122 writer.println("Car Telemetry service");
123 }
Rui Qiuf6668202021-04-08 15:37:20 -0700124
125 /**
126 * Registers a listener with CarTelemetryService for the service to send data to cloud app.
127 */
128 @Override
129 public void setListener(@NonNull ICarTelemetryServiceListener listener) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700130 // TODO(b/184890506): verify that only a hardcoded app can set the listener
Rui Qiuf6668202021-04-08 15:37:20 -0700131 mContext.enforceCallingOrSelfPermission(
132 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
Rui Qiu9b9341c2021-08-25 10:39:04 -0700133 mTelemetryHandler.post(() -> {
134 if (DEBUG) {
135 Slog.d(CarLog.TAG_TELEMETRY, "Setting the listener for car telemetry service");
136 }
137 mListener = listener;
138 });
Rui Qiuf6668202021-04-08 15:37:20 -0700139 }
140
141 /**
142 * Clears the listener registered with CarTelemetryService.
143 */
144 @Override
145 public void clearListener() {
146 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700147 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "clearListener");
148 mTelemetryHandler.post(() -> {
149 if (DEBUG) {
150 Slog.d(CarLog.TAG_TELEMETRY, "Clearing the listener for car telemetry service");
151 }
152 mListener = null;
153 });
Rui Qiuf6668202021-04-08 15:37:20 -0700154 }
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700155
156 /**
Rui Qiu9b9341c2021-08-25 10:39:04 -0700157 * Send a telemetry metrics config to the service.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700158 *
Rui Qiu9b9341c2021-08-25 10:39:04 -0700159 * @param key the unique key to identify the MetricsConfig.
160 * @param config the serialized bytes of a MetricsConfig object.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700161 */
162 @Override
Rui Qiu9b9341c2021-08-25 10:39:04 -0700163 public void addMetricsConfig(@NonNull MetricsConfigKey key, @NonNull byte[] config) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700164 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700165 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "addMetricsConfig");
Rui Qiu9b9341c2021-08-25 10:39:04 -0700166 mTelemetryHandler.post(() -> {
Rui Qiuf721b132021-09-10 12:41:09 -0700167 Slog.d(CarLog.TAG_TELEMETRY, "Adding metrics config " + key.getName()
168 + " to car telemetry service");
169 // TODO(b/199540952): If config is active, add it to DataBroker
170 TelemetryProto.MetricsConfig metricsConfig = null;
171 int status = ERROR_METRICS_CONFIG_UNKNOWN;
Rui Qiu9b9341c2021-08-25 10:39:04 -0700172 try {
173 metricsConfig = TelemetryProto.MetricsConfig.parseFrom(config);
Rui Qiu9b9341c2021-08-25 10:39:04 -0700174 } catch (InvalidProtocolBufferException e) {
175 Slog.e(CarLog.TAG_TELEMETRY, "Failed to parse MetricsConfig.", e);
176 status = ERROR_METRICS_CONFIG_PARSE_FAILED;
177 }
Rui Qiuf721b132021-09-10 12:41:09 -0700178 // if config can be parsed, add it to persistent storage
179 if (metricsConfig != null) {
180 status = mMetricsConfigStore.addMetricsConfig(metricsConfig);
181 }
182 // If no error (a config is successfully added), script results from an older version
183 // should be deleted
184 if (status == ERROR_METRICS_CONFIG_NONE) {
185 mResultStore.deleteResult(key.getName());
186 }
Rui Qiu9b9341c2021-08-25 10:39:04 -0700187 try {
188 mListener.onAddMetricsConfigStatus(key, status);
189 } catch (RemoteException e) {
190 Slog.d(CarLog.TAG_TELEMETRY, "error with ICarTelemetryServiceListener", e);
191 }
192 });
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700193 }
194
195 /**
Rui Qiuf721b132021-09-10 12:41:09 -0700196 * Removes a metrics config based on the key. This will also remove outputs produced by the
197 * MetricsConfig.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700198 */
199 @Override
Rui Qiu9b9341c2021-08-25 10:39:04 -0700200 public void removeMetricsConfig(@NonNull MetricsConfigKey key) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700201 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700202 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "removeMetricsConfig");
Rui Qiu9b9341c2021-08-25 10:39:04 -0700203 mTelemetryHandler.post(() -> {
Rui Qiuf721b132021-09-10 12:41:09 -0700204 Slog.d(CarLog.TAG_TELEMETRY, "Removing metrics config " + key.getName()
205 + " from car telemetry service");
Rui Qiu9b9341c2021-08-25 10:39:04 -0700206 // TODO(b/198792767): Check both config name and config version for deletion
Rui Qiuf721b132021-09-10 12:41:09 -0700207 // TODO(b/199540952): Stop and remove config from data broker
208 mResultStore.deleteResult(key.getName()); // delete the config's script results
Rui Qiu9b9341c2021-08-25 10:39:04 -0700209 boolean success = mMetricsConfigStore.deleteMetricsConfig(key.getName());
210 try {
211 mListener.onRemoveMetricsConfigStatus(key, success);
212 } catch (RemoteException e) {
213 Slog.d(CarLog.TAG_TELEMETRY, "error with ICarTelemetryServiceListener", e);
214 }
215 });
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700216 }
217
218 /**
Rui Qiuf721b132021-09-10 12:41:09 -0700219 * Removes all MetricsConfigs. This will also remove all MetricsConfig outputs.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700220 */
221 @Override
Rui Qiu9b9341c2021-08-25 10:39:04 -0700222 public void removeAllMetricsConfigs() {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700223 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700224 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "removeAllMetricsConfig");
225 mTelemetryHandler.post(() -> {
Rui Qiuf721b132021-09-10 12:41:09 -0700226 // TODO(b/199540952): Stop and remove all configs from DataBroker
227 Slog.d(CarLog.TAG_TELEMETRY,
228 "Removing all metrics config from car telemetry service");
229 mMetricsConfigStore.deleteAllMetricsConfigs();
230 mResultStore.deleteAllResults();
Rui Qiu9b9341c2021-08-25 10:39:04 -0700231 });
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700232 }
233
234 /**
235 * Sends script results associated with the given key using the
236 * {@link ICarTelemetryServiceListener}.
237 */
238 @Override
Rui Qiu9b9341c2021-08-25 10:39:04 -0700239 public void sendFinishedReports(@NonNull MetricsConfigKey key) {
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700240 // TODO(b/184087869): Implement
241 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700242 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "sendFinishedReports");
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700243 if (DEBUG) {
Rui Qiuf721b132021-09-10 12:41:09 -0700244 Slog.d(CarLog.TAG_TELEMETRY, "Flushing reports for a metrics config");
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700245 }
246 }
247
248 /**
Rui Qiu9b9341c2021-08-25 10:39:04 -0700249 * Sends all script results or errors using the {@link ICarTelemetryServiceListener}.
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700250 */
251 @Override
252 public void sendAllFinishedReports() {
253 // TODO(b/184087869): Implement
254 mContext.enforceCallingOrSelfPermission(
Rui Qiu9b9341c2021-08-25 10:39:04 -0700255 Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "sendAllFinishedReports");
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700256 if (DEBUG) {
Rui Qiu9b9341c2021-08-25 10:39:04 -0700257 Slog.d(CarLog.TAG_TELEMETRY, "Flushing all reports");
Rui Qiu9bc1bb92021-04-08 15:41:48 -0700258 }
259 }
260
Rui Qiu9b9341c2021-08-25 10:39:04 -0700261 @VisibleForTesting
262 Handler getTelemetryHandler() {
263 return mTelemetryHandler;
Rui Qiuebfbcfb2021-05-18 17:01:27 -0700264 }
Rui Qiuf721b132021-09-10 12:41:09 -0700265
266 @VisibleForTesting
267 ResultStore getResultStore() {
268 return mResultStore;
269 }
270
271 @VisibleForTesting
272 MetricsConfigStore getMetricsConfigStore() {
273 return mMetricsConfigStore;
274 }
Max Dashoukff9ffbc2021-02-16 11:36:39 -0800275}