aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhomart Mukhamejanov <zhomart@google.com>2021-05-20 11:42:19 -0700
committerZhomart Mukhamejanov <zhomart@google.com>2021-05-26 12:28:04 -0700
commitee8c0de97db03e775f7654c3445a125dd18e7db1 (patch)
treef2894f9e8fcdba3f118cc9efaaa587509f285e04
parent920ed595ce21c05384e189ef3fc407418da5cbf4 (diff)
downloadCar-ee8c0de97db03e775f7654c3445a125dd18e7db1.tar.gz
Change the format of the Manifest.
- Delete LogcatReader, we will add Publishers later. - Rename CarTelemetryService Manifest proto usage, this component will be updated later again when Controller, Broker components are added. Test: m -j CarService Bug: 187525360 Change-Id: I1be7badf90a76a47ee2f4a4dc90ea9395dfe6e51
-rw-r--r--.clang-format4
-rw-r--r--service/src/com/android/car/telemetry/CarTelemetryService.java24
-rw-r--r--service/src/com/android/car/telemetry/LogFilter.java205
-rw-r--r--service/src/com/android/car/telemetry/LogcatReader.java302
-rw-r--r--service/src/com/android/car/telemetry/proto/telemetry.proto251
-rw-r--r--tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java28
6 files changed, 61 insertions, 753 deletions
diff --git a/.clang-format b/.clang-format
index 30e9edabbf..b652e192de 100644
--- a/.clang-format
+++ b/.clang-format
@@ -36,3 +36,7 @@ IncludeCategories:
- Regex: '^".*'
Priority: 1
---
+Language: Proto
+BasedOnStyle: Google
+ColumnLimit: 100
+---
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index 0e34f902c7..695e25e772 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -44,6 +44,8 @@ import java.util.Map;
*/
public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
+ // TODO(b/189340793): Rename Manifest to MetricsConfig
+
private static final boolean DEBUG = false;
private static final int DEFAULT_VERSION = 0;
private static final String TAG = CarTelemetryService.class.getSimpleName();
@@ -103,16 +105,16 @@ public class CarTelemetryService extends ICarTelemetryService.Stub implements Ca
/**
* Allows client to send telemetry manifests.
*
- * @param key the unique key to identify the manifest.
- * @param manifest the serialized bytes of a Manifest object.
+ * @param key the unique key to identify the manifest.
+ * @param config the serialized bytes of a Manifest object.
* @return {@link AddManifestError} the error code.
*/
@Override
- public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] manifest) {
+ public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] config) {
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
synchronized (mLock) {
- return addManifestLocked(key, manifest);
+ return addManifestLocked(key, config);
}
}
@@ -197,9 +199,9 @@ public class CarTelemetryService extends ICarTelemetryService.Stub implements Ca
}
@GuardedBy("mLock")
- private @AddManifestError int addManifestLocked(ManifestKey key, byte[] manifest) {
+ private @AddManifestError int addManifestLocked(ManifestKey key, byte[] configProto) {
if (DEBUG) {
- Slog.d(TAG, "Adding manifest to car telemetry service");
+ Slog.d(TAG, "Adding MetricsConfig to car telemetry service");
}
int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
if (currentVersion > key.getVersion()) {
@@ -208,17 +210,17 @@ public class CarTelemetryService extends ICarTelemetryService.Stub implements Ca
return ERROR_SAME_MANIFEST_EXISTS;
}
- TelemetryProto.Manifest parsedManifest;
+ TelemetryProto.MetricsConfig metricsConfig;
try {
- parsedManifest = TelemetryProto.Manifest.parseFrom(manifest);
+ metricsConfig = TelemetryProto.MetricsConfig.parseFrom(configProto);
} catch (InvalidProtocolBufferException e) {
- Slog.e(TAG, "Failed to parse manifest.", e);
+ Slog.e(TAG, "Failed to parse MetricsConfig.", e);
return ERROR_PARSE_MANIFEST_FAILED;
}
mNameVersionMap.put(key.getName(), key.getVersion());
- // TODO(b/186047142): Store the manifest to disk
- // TODO(b/186047142): Send parsedManifest to a script manager or a queue
+ // TODO(b/186047142): Store the MetricsConfig to disk
+ // TODO(b/186047142): Send metricsConfig to a script manager or a queue
return ERROR_NONE;
}
diff --git a/service/src/com/android/car/telemetry/LogFilter.java b/service/src/com/android/car/telemetry/LogFilter.java
deleted file mode 100644
index 8f72fe84cf..0000000000
--- a/service/src/com/android/car/telemetry/LogFilter.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.telemetry;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.util.Log;
-
-import com.android.car.telemetry.TelemetryProto.LogListener;
-import com.android.car.telemetry.TelemetryProto.Manifest;
-
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * Encapsulates a filter that can be matched on log entries. Contains builder function to create
- * list of LogFilter given the loglistener.
- */
-public final class LogFilter {
-
- private static final String TAG = LogFilter.class.getSimpleName();
-
- /**
- * Types of filters to match against the logs. Different filter types will match in different
- * ways.
- */
- @Retention(SOURCE)
- @IntDef({FILTER_TAG, SUBSTRING})
- @interface FilterType {}
- static final int FILTER_TAG = 0;
- static final int SUBSTRING = 1;
-
- private final int mLogListenerIndex;
- private final @FilterType int mFilterType;
- private final String mFilter;
-
- LogFilter(int logListenerIndex, @FilterType int filterType, String filter) {
- this.mLogListenerIndex = logListenerIndex;
- this.mFilterType = filterType;
- if (filter == null) {
- throw new NullPointerException("Null filter");
- }
- this.mFilter = filter;
- }
-
- int getLogListenerIndex() {
- return mLogListenerIndex;
- }
-
- @LogFilter.FilterType int getFilterType() {
- return mFilterType;
- }
-
- String getFilter() {
- return mFilter;
- }
-
- /**
- * Creates a LogFilter instance.
- *
- * @param logListenerIndex the index of the logListener associated with the filter.
- * @param filterType the type of filter.
- * @param filter the value of the filter.
- * @return created LogFilter instance.
- */
- static LogFilter create(int logListenerIndex, @FilterType int filterType, String filter) {
- return new LogFilter(logListenerIndex, filterType, filter);
- }
-
- /**
- * Builds a List of {@link LogFilter} instances from {@link Manifest} and the logListener name.
- *
- * @param manifest {@link Manifest} file that contains list of logListeners.
- * @param logListenerName the name of the logListener as registered in the {@link Manifest}.
- * @return List of {@link LogFilter} instances.
- */
- static List<LogFilter> buildFilters(Manifest manifest, String logListenerName) {
- int logListenerIndex = getLogListenerIndexFromName(manifest, logListenerName);
- if (logListenerIndex == -1) {
- Log.w(TAG, "log listener with name " + logListenerName
- + " does not exist in manifest.");
- return Collections.unmodifiableList(new ArrayList<>());
- }
-
- List<LogFilter> result = new ArrayList<>();
- result.addAll(
- manifest.getLogListeners(logListenerIndex).getTagsList().stream()
- .map(tag -> LogFilter.create(logListenerIndex, FILTER_TAG, tag))
- .collect(Collectors.toList()));
- result.addAll(
- manifest.getLogListeners(logListenerIndex).getTypesList().stream()
- .map(LogFilter::typeToFilter)
- .filter(Optional::isPresent)
- .map(filter ->
- LogFilter.create(logListenerIndex, SUBSTRING, filter.get()))
- .collect(Collectors.toList()));
- return Collections.unmodifiableList(result);
- }
-
- /**
- * Gets the index of the {@link LogListener} in the manifest's list of logListeners.
- * Returns -1 if not found.
- *
- * @param manifest the {@link Manifest} that contains the definitions of the logListeners.
- * @param logListenerName name of the {@link LogListener} to get index for.
- * @return index of the logListener, -1 if not found.
- */
- static int getLogListenerIndexFromName(Manifest manifest, String logListenerName) {
- for (int i = 0; i < manifest.getLogListenersCount(); i++) {
- LogListener listener = manifest.getLogListeners(i);
- if (listener.getName().equals(logListenerName)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Converts log message filter {@link LogListener.Type} to corresponding filter string.
- *
- * @param type the filter {@link LogListener.Type}.
- * @return the corresponding filter string for the logListener type.
- */
- private static Optional<String> typeToFilter(LogListener.Type type) {
- switch (type) {
- case TYPE_UNSPECIFIED:
- return Optional.empty();
- case EXCEPTIONS:
- return Optional.of("Exception: ");
- }
- return Optional.empty();
- }
-
- /**
- * Matches in different ways against {@link LogcatReader.LogEntry} components depending on
- * filterType.
- *
- * @param entry the {@link LogcatReader.LogEntry} whose components will be matched against the
- * filters.
- * @return boolean denoting whether the filter can match the {@link LogcatReader.LogEntry}.
- */
- boolean matches(LogcatReader.LogEntry entry) {
- switch (getFilterType()) {
- case FILTER_TAG:
- return entry.mTag.equals(getFilter());
- case SUBSTRING:
- return entry.mMessage.contains(getFilter());
- }
- return false;
- }
-
- @Override
- public String toString() {
- return "LogFilter{"
- + "mLogListenerIndex=" + mLogListenerIndex + ", "
- + "mFilterType=" + mFilterType + ", "
- + "mFilter=" + mFilter
- + "}";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof LogFilter) {
- LogFilter that = (LogFilter) o;
- return this.mLogListenerIndex == that.getLogListenerIndex()
- && this.mFilterType == that.getFilterType()
- && this.mFilter.equals(that.getFilter());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int hash = 1;
- hash *= 1000003;
- hash ^= mLogListenerIndex;
- hash *= 1000003;
- hash ^= Integer.hashCode(mFilterType);
- hash *= 1000003;
- hash ^= mFilter.hashCode();
- return hash;
- }
-}
-
diff --git a/service/src/com/android/car/telemetry/LogcatReader.java b/service/src/com/android/car/telemetry/LogcatReader.java
deleted file mode 100644
index a83a72e412..0000000000
--- a/service/src/com/android/car/telemetry/LogcatReader.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.telemetry;
-
-import android.annotation.Nullable;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.ObjIntConsumer;
-import java.util.function.Supplier;
-
-/**
- * Reads Android logs while there are log listeners registered to it and sends the event through the
- * mLogEventConsumer.
- */
-public class LogcatReader {
- private static final String TAG = LogcatReader.class.getSimpleName();
-
- // TODO(b/180515554). Find a proper place for LOG_* constants.
- // They will be used in ScriptExecutor as well.
- /** The value of key to retrieve log seconds since epoch time from bundle. */
- private static final String LOG_SEC_KEY = "log.sec";
-
- /** The value of key to retrieve log nanoseconds from bundle. */
- private static final String LOG_NSEC_KEY = "log.nsec";
-
- /** The value of key to retrieve log tag from bundle. */
- private static final String LOG_TAG_KEY = "log.tag";
-
- /** The value of key to retrieve log message from bundle. */
- private static final String LOG_MESSAGE_KEY = "log.message";
-
- // Defined in system/core/liblog/include/log/log_read.h
- private static final int LOGGER_ENTRY_MAX_LEN = 5 * 1024;
-
- // The entry sizes differ in Android 10. See
- // https://cs.android.com/android/platform/superproject/+/android-10.0.0_r30:system/core/liblog/include/log/log_read.h
- public static final int ENTRY_V1_SIZE = 20;
- public static final int ENTRY_V2_V3_SIZE = 24;
- public static final int ENTRY_V4_SIZE = 28;
-
- private final AtomicBoolean mRunning = new AtomicBoolean(false);
-
- private final ObjIntConsumer<Bundle> mLogEventConsumer;
- private final Supplier<LocalSocket> mLocalSocketSupplier;
- private final Executor mExecutor;
-
- private final HashSet<LogFilter> mLogFilters = new HashSet<>();
-
- private synchronized boolean logFiltersEmpty() {
- return mLogFilters.isEmpty();
- }
-
- /**
- * Replicates {@code struct log_msg} from system/core/liblog/include/log/log_read.h and {@code
- * struct AndroidLogEntry} from system/core/liblog/include/log/logprint.h.
- */
- static class LogEntry {
- long mTvSec; // seconds since Epoch
- long mTvNSec; // nanoseconds
- int mPid; // generating process's pid
- long mTid; // generating process's tid
- long mUid; // generating process's uid
- int mPriority; // log priority, e.g. {@link Log#INFO}.
- String mTag;
- String mMessage;
-
- /**
- * Parses raw bytes received from {@code logd}.
- *
- * @param data raw bytes
- * @param readSize number of bytes received from logd.
- */
- @Nullable
- static LogEntry parse(byte[] data, int readSize) {
- // Parsing log_msg struct defined in system/core/liblog/include/log/log_read.h.
- // Only first headerSize is used to create LogEntry. Following message messageSize bytes
- // define log message.
- ByteBuffer dataBytes = ByteBuffer.wrap(data);
- dataBytes.order(ByteOrder.LITTLE_ENDIAN);
- int messageSize = dataBytes.getShort();
- int headerSize = dataBytes.getShort();
- if (readSize < messageSize + headerSize) {
- Log.w(
- TAG, "Invalid log message size "
- + (messageSize + headerSize)
- + ", received only "
- + readSize);
- return null;
- }
- LogEntry entry = new LogEntry();
- entry.mPid = dataBytes.getInt();
- entry.mTid = dataBytes.getInt();
- entry.mTvSec = dataBytes.getInt();
- entry.mTvNSec = dataBytes.getInt();
- if (headerSize >= ENTRY_V2_V3_SIZE) {
- dataBytes.position(dataBytes.position() + 4); // lid is not used here.
- }
- if (headerSize >= ENTRY_V4_SIZE) {
- entry.mUid = dataBytes.getInt();
- }
-
- // Parsing log message.
- // See android_log_processLogBuffer() in system/core/liblog/logprint.cpp for details.
- // message format: <priority:1><tag:N>\0<message:N>\0
- // TODO(b/180516393): improve message parsing that were not transferred
- // from the cpp above. Also verify this mechanism is ok from selinux perspective.
-
- if (messageSize < 3) {
- Log.w(TAG, "Log message is too small, size=" + messageSize);
- return null;
- }
- if (headerSize != dataBytes.position()) {
- Log.w(TAG, "Invalid header size " + headerSize + ", expected "
- + dataBytes.position());
- return null;
- }
- int msgStart = -1;
- int msgEnd = -1;
- for (int i = 1; i < messageSize; i++) {
- if (data[headerSize + i] == 0) {
- if (msgStart == -1) {
- msgStart = i + 1 + headerSize;
- } else {
- msgEnd = i + headerSize;
- break;
- }
- }
- }
- if (msgStart == -1) {
- Log.w(TAG, "Invalid log message");
- return null;
- }
- if (msgEnd == -1) {
- msgEnd = Math.max(msgStart, messageSize - 1);
- }
- entry.mPriority = data[headerSize];
- entry.mTag =
- new String(data, headerSize + 1, msgStart - headerSize - 2,
- StandardCharsets.US_ASCII);
- entry.mMessage =
- new String(data, msgStart, msgEnd - msgStart, StandardCharsets.US_ASCII);
- return entry;
- }
- }
-
- /**
- * Constructs {@link LogcatReader}.
- *
- * @param logEventConsumer a consumer that's called when a filter matches a log.
- * @param localSocketSupplier a supplier for LocalSocket to connect logd.
- * @param executor an {@link Executor} to run the LogcatReader instance.
- */
- public LogcatReader(
- ObjIntConsumer<Bundle> logEventConsumer,
- Supplier<LocalSocket> localSocketSupplier,
- Executor executor) {
- this.mLogEventConsumer = logEventConsumer;
- this.mLocalSocketSupplier = localSocketSupplier;
- this.mExecutor = executor;
- }
-
- /** Runs {@link LogcatReader}. */
- private void run() {
- Log.d(TAG, "Running LogcatReader");
-
- // Under the hood, logcat receives logs from logd, to remove the middleman, LogcatReader
- // doesn't run logcat, but directly connects to logd socket and parses raw logs.
- try (LocalSocket socket = mLocalSocketSupplier.get()) {
- // Connect to /dev/socket/logdr
- socket.connect(new LocalSocketAddress("logdr", LocalSocketAddress.Namespace.RESERVED));
- try (OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
- InputStream reader = socket.getInputStream()) {
- // Ask for streaming log and set tail=1 to get only new logs.
- // See system/core/liblog/logd_reader.cpp for example on how to interact with logdr.
- writer.write("stream tail=1");
- writer.flush();
- Log.d(TAG, "Sent request to logd and awaiting for logs");
-
- byte[] data = new byte[LOGGER_ENTRY_MAX_LEN + 1];
- while (!logFiltersEmpty()) {
- int n = reader.read(data, 0, LOGGER_ENTRY_MAX_LEN);
- if (n == -1) {
- Log.e(TAG, "Disconnected from logd");
- return;
- }
- LogEntry entry = LogEntry.parse(data, n);
- if (entry == null) {
- continue;
- }
-
- // Ignore the logs from the telemetry service. This
- // makes sure a recursive log storm does not happen - i.e. app produces a log
- // which in turn executes a code path that produces another log.
- if (entry.mUid == Process.myUid()) {
- continue;
- }
- // Check if it's running before processing the logs, because by the time we get
- // here ScriptExecutor might get disconnected.
- if (!mRunning.get()) {
- Log.d(TAG, "Not running anymore, exiting.");
- return;
- }
- // Keep track of which logListener an event for this entry has been sent,
- // so that the same entry isn't sent multiple times for the same logListener
- // if its multiple filters match.
- HashSet<Integer> sentLogListenerIndices = new HashSet<>();
- for (LogFilter filter : mLogFilters) {
- if (!sentLogListenerIndices.contains(filter.getLogListenerIndex())
- && filter.matches(entry)) {
- sentLogListenerIndices.add(filter.getLogListenerIndex());
- sendLogEvent(filter.getLogListenerIndex(), entry);
- }
- }
- }
- Log.d(TAG, "Log filters are empty, exiting.");
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to connect to logd", e);
- } finally {
- mRunning.set(false);
- }
- }
-
- /**
- * Sends the log event to the through the mLogEventConsumer.
- *
- * @param logListenerIndex the index of the logListener, whose function will receive the log
- * event.
- * @param entry the LogEntry instance to be bundled up and sent as event.
- */
- private void sendLogEvent(int logListenerIndex, LogEntry entry) {
- Bundle event = new Bundle();
- event.putLong(LOG_SEC_KEY, entry.mTvSec);
- event.putLong(LOG_NSEC_KEY, entry.mTvNSec);
- event.putString(LOG_TAG_KEY, entry.mTag);
- event.putString(LOG_MESSAGE_KEY, entry.mMessage);
- mLogEventConsumer.accept(event, logListenerIndex);
- }
-
- /**
- * Subscribes the list of {@link LogFilter} instances.
- *
- * @param newLogFilters the list of new log filters to be added to mLogFilters.
- */
- synchronized void subscribeLogFilters(List<LogFilter> newLogFilters) {
- mLogFilters.addAll(newLogFilters);
- }
-
- /**
- * Unsubscribes all {@link LogFilter} associated with the logListenerIndex
- *
- * @param logListenerIndex the index of the logListener to unregister.
- */
- synchronized void unsubscribeLogListener(int logListenerIndex) {
- mLogFilters.removeIf(lf -> lf.getLogListenerIndex() == logListenerIndex);
- }
-
- /** Starts the run method in a new thread if logcatReader isn't running already. */
- void startAsyncIfNotStarted() {
- if (mRunning.compareAndSet(false, true)) {
- mExecutor.execute(this::run);
- }
- }
-
- /** Gracefully stops {@link LogcatReader}. */
- synchronized void stop() {
- mRunning.set(false);
- mLogFilters.clear();
- }
-
- /** Builds a {@link LocalSocket} to read from {@code logdr}. */
- static LocalSocket buildLocalSocket() {
- return new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
- }
-}
diff --git a/service/src/com/android/car/telemetry/proto/telemetry.proto b/service/src/com/android/car/telemetry/proto/telemetry.proto
index 422c4a2c33..5787d62b9f 100644
--- a/service/src/com/android/car/telemetry/proto/telemetry.proto
+++ b/service/src/com/android/car/telemetry/proto/telemetry.proto
@@ -21,50 +21,35 @@ package com.android.car.telemetry;
option java_package = "com.android.car.telemetry";
option java_outer_classname = "TelemetryProto";
-// A Tpk (Telemetry Package) manifest.
-// It contains a script and the rules how the script runs on devices.
-message Manifest {
+// A metrics configuration.
+//
+// The metrics configuration describes a metric that is collected from a device.
+// It includes a declarative part that configures the metric and the data publisher
+// and a data handler to process the data and create a statistic.
+// The latter is written in Lua language.
+message MetricsConfig {
// Required.
- // Name of the Tpk, used to distinguish TPKs.
+ // The name of the configuration. Must be unique within a device.
// Only alphanumeric and _ characters are allowed. Minimum length is 3 chars.
optional string name = 1;
// Required.
- // A script that is executed in devices. Must contain all the functions
- // defined in the listeners below.
- optional string script = 2;
+ // Version number of the configuration.
+ optional int32 version = 2;
// Required.
- // A unique version number of the Tpk, used to distinguish between Tpks of the
- // same name.
- optional int32 version = 3;
-
- // Telemetry service subscribes these listeners to vehicle property change events.
- // The functions must be present in the script.
- repeated PropertyChangeListener property_change_listeners = 4;
-
- // Telemetry service subscribes these listeners to Android log (logcat) events.
- // The functions must be present in the script.
- repeated LogListener log_listeners = 5;
-
- // Telemetry service subscribes these listeners to stats anomalies, such as
- // Alerts, Alarms, stats out-of-space anomaly and historical data anomaly.
- // The number of listener is limited to 10 by statsd.
- // The functions must be present in the script.
- repeated StatsListener stats_listeners = 6;
-
- // Dumpsys result listeners can be registered to retrieve dump report for
- // specified report types.
- // The functions must be present in the script.
- repeated DumpsysResultListener dumpsys_result_listeners = 7;
+ // A script that is executed in devices. Must contain all the handler functions
+ // defined in the listeners below.
+ // The script functions must be `pure` functions.
+ optional string script = 3;
- // This timer executes functions when a specific event happens.
- // The functions must be present in the script.
- repeated Timer timers = 8;
+ // Required.
+ repeated Subscriber subscribers = 4;
}
-// A function that is executed when a vehicle property change events occur.
-message PropertyChangeListener {
+// Parameters for Vehicle Properties publisher.
+// See https://source.android.com/devices/automotive/vhal/properties
+message VehiclePropertyPublisher {
// Required.
// See packages/services/Car/car-lib/src/android/car/VehiclePropertyIds.java
optional int32 vehicle_property_id = 1;
@@ -73,197 +58,21 @@ message PropertyChangeListener {
// packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
// look for constants SENSOR_RATE_*;
optional float read_rate = 2;
-
- // Required.
- optional string function_name = 3;
}
-// A function that receives Android log (logcat) events. The log event is passed
-// as a string argument to the function.
-//
-// The LogListener will receive log events if the log event matches any of the
-// "types" or "tags".
-//
-// Please see ../README.md for details.
-//
-// Example:
-// function processException(log_event_line) ... end
-message LogListener {
- enum Type {
- // Default value.
- TYPE_UNSPECIFIED = 0;
-
- // Matches logged exceptions.
- EXCEPTIONS = 1;
+// Specifies data publisher and its parameters.
+message Publisher {
+ oneof publisher {
+ VehiclePropertyPublisher vehicle_property = 1;
}
-
- // Required.
- // Unique name of the logListener within the Tpk. Used to
- // subscribe/unsubscribe from log events.
- optional string name = 1;
-
- // Required.
- // Name of the function to be executed when the logs the logListener has a
- // match with its filters
- optional string function_name = 2;
-
- // Message types to listen to in LogCat.
- // At least one "types" or "tags" must be provided.
- repeated Type types = 3;
-
- // Tags to listen to in LogCat.
- // At least one "types" or "tags" must be provided.
- repeated string tags = 4;
}
-// A function that receives stats reports.
-//
-// LogProcessor App provides limited statsd support. Please see
-// logprocessor/README.md for details.
-//
-// Script function semantics:
-// -- Param report_list is a table with 1-1 mapping
-// to ConfigMetricsReportList.
-// -- Param extra_stats is a table { config_uid, config_key, ... } coming
-// -- from PendingIntent described in StatsManager#setBroadcastSubscriber().
-// function onStatdEvent(report_list, extra_stats) end
-message StatsListener {
- // Function to be called when the subscriptions below get triggered.
- optional string function_name = 1;
-
- // Serialized StatsdConfig defined in
- // AOSP/frameworks/base/cmds/statsd/src/statsd_config.proto
- // NOTE: Config ID and other generated IDs must be unique within this
- // statsd_config.
- optional bytes statsd_config = 2;
-
- // Subscribe the telemetry service to stats broadcast events: Alarms and Alerts.
- // Subscriptions must be defined in the statsd_config as
- // BroadcastSubscriberDetails.
- // NOTE: It must be unique within the statsd_config.
- optional int64 subscriber_id = 3;
-}
-
-// A function that receives Dumpsys reports.
-//
-// The DumpsysResultListener will receive dumpsys reports of the specified
-// DumpsysReportType
-message DumpsysResultListener {
- // Names of the system services that's allowed to run dumpsys on.
- enum SystemServiceName {
- UNSPECIFIED = 0;
-
- // Matches car service com.android.car.CarService.
- CAR_SERVICE = 1;
-
- // Matches package manager service
- // com.android.server.pm.PackageManagerService.
- PACKAGE = 2; //
- }
-
- // Required.
- // Unique name of the DumpsysResultListener within the Tpk.
- // Used to register the specific DumpsysResultListener needed.
- optional string name = 1;
-
- // Required.
- // Name of the function to be executed when a dumpsys report of the specified
- // system services are retrieved.
- optional string function_name = 2;
-
- // Required.
- // System service to run dumpsys for.
- optional SystemServiceName system_service_name = 3;
-
- // Extra arguments for dumpsys
- optional string arguments = 4;
-}
-
-// Runs a script function after some delay when an event happens.
-message Timer {
- enum TriggerType {
- TRIGGER_TYPE_UNSPECIFIED = 0;
-
- // When the device boots up.
- //
- // Note that when device wakes up from a deep sleep (suspend to ram), this
- // trigger doesn't work.
- //
- // It doesn't guarantee immediate activation of the timer right after the
- // boot, only after the system and the script is ready.
- // "initial_delay_millis" parameter denotes a delay from boot (not from
- // the script is initialized and ready).
- TRIGGER_TYPE_BOOT = 1;
- }
-
- // Required.
- // Name of the script function that will be executed.
- optional string function_name = 1;
-
- // Required.
- // An event trigger that activates this timer.
- optional TriggerType trigger_type = 2;
-
- // Required.
- // Delay after the trigger event before initial executing the function.
- //
- // Be careful putting long delays (>30 minutes), because the average
- // driving duration might be shorter than the delay, and the function
- // will be executed less frequently than desired amount.
- optional int64 initial_delay_millis = 3;
-
- // The max number of times the function will be periodically executed.
- // When this number of execution is reached, the timer will be stopped.
- // 0 means the timer is disabled.
- // -1 means the timer never stops.
- optional int32 max_count = 4;
-
- // Time between successive function executions if max_count >= 2.
- optional int64 period_millis = 5;
-}
-
-// A message that encapsulates different types of error or log metadata as
-// for informational and debugging purposes.
-//
-// When the app crashes or the system restarts, the timers will reset.
-message SecularTrendsLog {
- // Required.
- optional int64 timestamp = 1;
-
- enum LogType {
- // Default enum.
- UNSPECIFIED = 0;
-
- // Used when manifest is misconfigurated, such as missing required fields.
- MANIFEST_MISCONFIGURATION = 1;
-
- // Used when a Java service throws an exception.
- JAVA_EXCEPTION = 2;
-
- // Used when LogProc service failes to bind to sandbox service.
- SANDBOX_SERVICE_CONNECTION_FAILURE = 3;
-
- // Used when an error occurs in the native code.
- NATIVE_RUNTIME_ERROR = 4;
-
- // Used when an error occurs while executing the Lua script (such as
- // errors returned by lua_pcall)
- LUA_RUNTIME_ERROR = 5;
-
- // Used when a service that telemetry service depends on crashes or fails.
- DEPENDENT_SERVICE_FAILURE = 6;
- }
-
- // Required.
- // A type that indicates where the log is generated.
- optional LogType type = 2;
-
- // Required.
- // Human readable message explaining what’s wrong or how to fix it.
- optional string message = 3;
+// Specifies publisher with its parameters and the handler function that's invoked
+// when data is received. The format of the data depends on the Publisher.
+message Subscriber {
+ // Name of the script function that's invoked when this subscriber is triggered.
+ optional string handler = 1;
- // Optional.
- // If there is an exception, there will be stack trace. However this
- // information is not always available.
- optional string stack_trace = 4;
+ // Publisher and its parameters.
+ optional Publisher publisher = 2;
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
index d8bf9a2bc0..0e9a1689dd 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
@@ -40,8 +40,8 @@ public class CarTelemetryServiceTest {
private final ManifestKey mManifestKeyV1 = new ManifestKey("Name", 1);
private final ManifestKey mManifestKeyV2 = new ManifestKey("Name", 2);
- private final TelemetryProto.Manifest mManifest =
- TelemetryProto.Manifest.newBuilder().setScript("no-op").build();
+ private final TelemetryProto.MetricsConfig mMetricsConfig =
+ TelemetryProto.MetricsConfig.newBuilder().setScript("no-op").build();
private CarTelemetryService mService;
@@ -52,16 +52,16 @@ public class CarTelemetryServiceTest {
@Test
public void testAddManifest_newManifest_shouldSucceed() {
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
@Test
public void testAddManifest_duplicateManifest_shouldFail() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS);
}
@@ -75,25 +75,25 @@ public class CarTelemetryServiceTest {
@Test
public void testAddManifest_olderManifest_shouldFail() {
- mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NEWER_MANIFEST_EXISTS);
}
@Test
public void testAddManifest_newerManifest_shouldReplace() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
@Test
public void testRemoveManifest_manifestExists_shouldSucceed() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
boolean result = mService.removeManifest(mManifestKeyV1);
@@ -109,15 +109,15 @@ public class CarTelemetryServiceTest {
@Test
public void testRemoveAllManifests_shouldSucceed() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
- mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
+ mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
mService.removeAllManifests();
// verify that the manifests are cleared by adding them again, should succeed
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
- result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
}