[automerger skipped] Merge "Import translations. DO NOT MERGE ANYWHERE" into stage-aosp-master am: 0477a27ad4 -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Car/+/20628676
Change-Id: Ie6cd95d1f3bdb325f4545d4fc954ef0c1ffdb102
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/FrameworkPackageStubs/res/values-en-rCA/strings.xml b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
index 92b3376..97c9277 100644
--- a/FrameworkPackageStubs/res/values-en-rCA/strings.xml
+++ b/FrameworkPackageStubs/res/values-en-rCA/strings.xml
@@ -3,6 +3,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="6179574017413146651">"Activity Stub"</string>
<string name="message_not_supported" msgid="133939962837892495">"No application can handle this action"</string>
- <string name="pip_not_supported" msgid="8681268258599412706">"Picture in Picture is not supported on this device"</string>
+ <string name="pip_not_supported" msgid="8681268258599412706">"Picture-in-picture is not supported on this device"</string>
<string name="stub_name" msgid="3987164490218189006">"None"</string>
</resources>
diff --git a/apex_car_framework/Android.bp b/apex_car_framework/Android.bp
index 0043ed5..24f6401 100644
--- a/apex_car_framework/Android.bp
+++ b/apex_car_framework/Android.bp
@@ -128,6 +128,7 @@
"android.car.media",
"android.car.navigation",
"android.car.occupantawareness",
+ "android.car.oem",
"android.car.os",
"android.car.projection",
"android.car.settings",
diff --git a/car-evs-helper-lib/Android.bp b/car-evs-helper-lib/Android.bp
new file mode 100644
index 0000000..f383376
--- /dev/null
+++ b/car-evs-helper-lib/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 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.
+
+// This project contains libraries that are used internally, mostly by
+// CarService and CarServiceHelperService.
+//
+// They're not meant to be used by other system apps and hence are not
+// supported.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_library {
+ name: "car-evs-helper-lib",
+ srcs: [
+ "src/**/*.java",
+ ],
+ libs: [
+ "android.car",
+ ],
+ platform_apis: true,
+ required : [
+ "libcarevsglrenderer_jni",
+ ],
+}
diff --git a/car-evs-helper-lib/AndroidManifest.xml b/car-evs-helper-lib/AndroidManifest.xml
new file mode 100644
index 0000000..ba31871
--- /dev/null
+++ b/car-evs-helper-lib/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.internal.evs" >
+</manifest>
diff --git a/car-evs-helper-lib/README.md b/car-evs-helper-lib/README.md
new file mode 100644
index 0000000..416a8a8
--- /dev/null
+++ b/car-evs-helper-lib/README.md
@@ -0,0 +1,82 @@
+<!--
+ Copyright (C) 2022 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
+ -->
+# car-evs-helper-lib
+This directory contains two modules that are used by other apps to process
+CarEvsBufferDescriptor and render its contents to the display with EGL.
+* `car-evs-helper-lib:` This library contains `CarEvsGLSurfaceView` and
+ `CarEvsBufferRenderer` classes.
+* `libcarevsglrenderer_jni`: This is a JNI library `CarEvsBufferRenderer` uses
+ to render the contents of `CarEvsBufferDescriptor` with EGL.
+## How to use
+Please follow below instructions to delegate a `CarEvsBufferDescriptor` rendering
+to this library. A reference implementation is also available at
+`packages/services/Car/tests/CarEvsCameraPreviewApp`.
+1. Make the application refer to `car-evs-helper-lib` and
+ `libcarevsglrenderer_jni` libraries by adding below lines to `Android.bp`.
+```
+static_libs: ["car-evs-helper-lib"],
+jni_libs: ["libcarevsglrenderer_jni"],
+```
+2. Implement `CarEvsGLSurfaceView.Callback` interface. For example,
+```
+/**
+ * This method is called by the renderer to fetch a new frame to draw.
+ */
+@Override
+public CarEvsBufferDescriptor getNewFrame() {
+ synchronized(mLock) {
+ // Return a buffer to render.
+ return mBufferToRender;
+ }
+}
+/**
+ * This method is called by the renderer when it is done with a passed
+ * CarEvsBufferDescriptor object.
+ */
+@Override
+public void returnBuffer(CarEvsBufferDescriptor buffer) {
+ // Return a buffer to CarEvsService.
+ try {
+ mEvsManager.returnFrameBuffer(buffer);
+ } catch (Exception e) {
+ ...
+ }
+ ...
+}
+```
+3. Create `CarEvsGLSurfaceView` with the application context,
+ `CarEvsGLSurfaceView.Callback` object, and, optionally, a desired in-plane
+ rotation angle.
+```
+private CarEvsGLSurfaceView mView;
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ ...
+ mView = CarEvsGLSurfaceView(getAppliation(), this, /* angleInDegree= */ 0);
+ ...
+}
+```
+4. Start a video stream and update wheneven new frame buffer arrives. For
+ example,
+```
+private final CarEvsManager.CarEvsStreamCallback mStreamHandler =
+ new CarEvsManager.CarEvsStreamCallback() {
+ ...
+ @Override
+ public void onNewFrame(CarEvsBufferDescriptor buffer) {
+ synchronized(mLock) {
+ mBufferToRender = buffer;
+ }
+ }
+}
+```
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp b/car-evs-helper-lib/jni/Android.bp
similarity index 91%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
rename to car-evs-helper-lib/jni/Android.bp
index d06620a..702a23e 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
+++ b/car-evs-helper-lib/jni/Android.bp
@@ -23,9 +23,7 @@
sdk_version: "current",
- srcs: [
- "CarEvsCameraPreviewRenderer.cpp",
- ],
+ srcs: ["./**/*.cpp"],
header_libs: ["jni_headers"],
@@ -43,7 +41,7 @@
},
cflags: [
- "-DLOG_TAG=\"CarEvsCameraRendererJNI\"",
+ "-DLOG_TAG=\"CarEvsBufferRendererJNI\"",
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
"-Wall",
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp b/car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
similarity index 84%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp
rename to car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
index 91ca40b..654703f 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/CarEvsCameraPreviewRenderer.cpp
+++ b/car-evs-helper-lib/jni/CarEvsBufferRenderer.cpp
@@ -20,19 +20,18 @@
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
-
#include <android/hardware_buffer_jni.h>
+
#include <jni.h>
namespace {
-const char kClassName[] = "com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer";
+const char kClassName[] = "com/android/car/internal/evs/GLES20CarEvsBufferRenderer";
EGLImageKHR gKHRImage = EGL_NO_IMAGE_KHR;
-jboolean nativeUpdateTexture(
- JNIEnv* env, jobject /*thiz*/, jobject hardwareBufferObj, jint textureId) {
-
+jboolean nativeUpdateTexture(JNIEnv* env, jobject /*thiz*/, jobject hardwareBufferObj,
+ jint textureId) {
EGLDisplay eglCurrentDisplay = eglGetCurrentDisplay();
if (gKHRImage != EGL_NO_IMAGE_KHR) {
// Release a previous EGL image
@@ -49,11 +48,8 @@
// Create EGL image from a native hardware buffer
EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID(nativeBuffer);
EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- gKHRImage = eglCreateImageKHR(eglCurrentDisplay,
- EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID,
- eglBuffer,
- eglImageAttributes);
+ gKHRImage = eglCreateImageKHR(eglCurrentDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ eglBuffer, eglImageAttributes);
if (gKHRImage == EGL_NO_IMAGE_KHR) {
return JNI_FALSE;
}
@@ -74,7 +70,7 @@
return JNI_TRUE;
}
-} // namespace unnamed
+} // namespace
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
JNIEnv* env;
@@ -85,7 +81,7 @@
// Registers native methods
static const JNINativeMethod methods[] = {
{"nUpdateTexture", "(Landroid/hardware/HardwareBuffer;I)Z",
- reinterpret_cast<void*>(nativeUpdateTexture)},
+ reinterpret_cast<void*>(nativeUpdateTexture)},
};
jclass clazz = env->FindClass(kClassName);
diff --git a/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java b/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java
new file mode 100644
index 0000000..c798ee3
--- /dev/null
+++ b/car-evs-helper-lib/src/com/android/car/internal/evs/CarEvsGLSurfaceView.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 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.internal.evs;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.car.evs.CarEvsBufferDescriptor;
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.view.MotionEvent;
+
+import com.android.internal.util.Preconditions;
+import com.android.car.internal.evs.GLES20CarEvsBufferRenderer;
+
+/**
+ * GPU-backed SurfaceView to render a hardware buffer described by {@link CarEvsBufferDescriptor}.
+ */
+public final class CarEvsGLSurfaceView extends GLSurfaceView {
+ private static final String TAG = CarEvsGLSurfaceView.class.getSimpleName();
+ private static final int DEFAULT_IN_PLANE_ROTATION_ANGLE = 0;
+
+ private final GLES20CarEvsBufferRenderer mRenderer;
+
+ /** An interface to pull and return {@code CarEvsBufferDescriptor} object to render. */
+ public interface BufferCallback {
+ /**
+ * Requests a new {@link CarEvsBufferDescriptor} to draw.
+ *
+ * This method may return a {@code null} if no new frame has been prepared since the last
+ * frame was drawn.
+ *
+ * @return {@link CarEvsBufferDescriptor} object to process.
+ */
+ @Nullable CarEvsBufferDescriptor onBufferRequested();
+
+ /**
+ * Notifies that the buffer is processed.
+ *
+ * @param buffer {@link CarEvsBufferDescriptor} object we are done with.
+ */
+ void onBufferProcessed(@NonNull CarEvsBufferDescriptor buffer);
+ }
+
+ private CarEvsGLSurfaceView(Context context, BufferCallback callback, int angleInDegree) {
+ super(context);
+ setEGLContextClientVersion(2);
+
+ mRenderer = new GLES20CarEvsBufferRenderer(context, callback, angleInDegree);
+ setRenderer(mRenderer);
+
+ setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+ }
+
+ /**
+ * Returns all buffers held by the renderer.
+ */
+ public void reset() {
+ mRenderer.clearBuffer();
+ }
+
+ /**
+ * Creates a {@link CarEvsGLSurfaceView} object with the default in-plane rotation angle.
+ *
+ * @param context Current appliation context.
+ * @param callback {@link CarEvsGLSurfaceView.BufferCallback} object.
+ *
+ */
+ public static CarEvsGLSurfaceView create(Context context, BufferCallback callback) {
+ return create(context, callback, DEFAULT_IN_PLANE_ROTATION_ANGLE);
+ }
+
+ /**
+ * Creates a {@link CarEvsGLSurfaceView} object with a given in-plane rotation angle in degree.
+ *
+ * @param context Current appliation context.
+ * @param callback {@link CarEvsGLSurfaceView.BufferCallback} object.
+ * @param angleInDegree In-plane counter-clockwise rotation angle in degree.
+ */
+ public static CarEvsGLSurfaceView create(Context context, BufferCallback callback,
+ int angleInDegree) {
+
+ Preconditions.checkArgument(context != null, "Context cannot be null.");
+ Preconditions.checkArgument(callback != null, "BufferCallback cannot be null.");
+
+ return new CarEvsGLSurfaceView(context, callback, angleInDegree);
+ }
+}
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java b/car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
similarity index 70%
rename from tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java
rename to car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
index f04d15b..8de69f1 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/GLES20CarEvsCameraPreviewRenderer.java
+++ b/car-evs-helper-lib/src/com/android/car/internal/evs/GLES20CarEvsBufferRenderer.java
@@ -14,37 +14,36 @@
* limitations under the License.
*/
-package com.google.android.car.evs;
+package com.android.car.internal.evs;
import static android.opengl.GLU.gluErrorString;
+import android.annotation.NonNull;
import android.car.evs.CarEvsBufferDescriptor;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
import android.hardware.HardwareBuffer;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
-import android.opengl.GLUtils;
import android.util.Log;
-import androidx.annotation.GuardedBy;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
-import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
- * GLES20 SurfaceView Renderer
+ * GLES20 SurfaceView Renderer for CarEvsBufferDescriptor.
*/
-public final class GLES20CarEvsCameraPreviewRenderer implements GLSurfaceView.Renderer {
- private static final String TAG = GLES20CarEvsCameraPreviewRenderer.class.getSimpleName();
+public final class GLES20CarEvsBufferRenderer implements GLSurfaceView.Renderer {
+
+ private static final String TAG = GLES20CarEvsBufferRenderer.class.getSimpleName()
+ .replace("GLES20", "");
+ private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static final int FLOAT_SIZE_BYTES = 4;
private static final float[] sVertCarPosData = {
@@ -66,49 +65,58 @@
0.0f, 0.0f, 0.0f, 1.0f };
private final String mVertexShader =
- "#version 300 es \n" +
- "layout(location = 0) in vec4 pos; \n" +
- "layout(location = 1) in vec2 tex; \n" +
- "uniform mat4 cameraMat; \n" +
- "out vec2 uv; \n" +
- "void main() \n" +
- "{ \n" +
- " gl_Position = cameraMat * pos; \n" +
- " uv = tex; \n" +
- "} \n";
+ "attribute vec4 pos; \n" +
+ "attribute vec2 tex; \n" +
+ "uniform mat4 cameraMat; \n" +
+ "varying vec2 uv; \n" +
+ "void main() \n" +
+ "{ \n" +
+ " gl_Position = cameraMat * pos; \n" +
+ " uv = tex; \n" +
+ "} \n";
private final String mFragmentShader =
- "#version 300 es \n" +
- "precision mediump float; \n" +
- "uniform sampler2D tex; \n" +
- "in vec2 uv; \n" +
- "out vec4 color; \n" +
- "void main() \n" +
- "{ \n" +
- " vec4 texel = texture(tex, uv); \n" +
- " color = texel; \n" +
- "} \n";
+ "precision mediump float; \n" +
+ "uniform sampler2D tex; \n" +
+ "varying vec2 uv; \n" +
+ "void main() \n" +
+ "{ \n" +
+ " gl_FragColor = texture2D(tex, uv); \n" +
+ "} \n";
private final Object mLock = new Object();
+ private final CarEvsGLSurfaceView.BufferCallback mCallback;
+ private final Context mContext;
+ private final FloatBuffer mVertCarPos;
+ private final FloatBuffer mVertCarTex;
- private CarEvsCameraPreviewActivity mActivity;
+ private int mProgram;
+ private int mTextureId;
+ private int mWidth;
+ private int mHeight;
+ // Native method to update the texture with a received frame buffer
@GuardedBy("mLock")
- private CarEvsBufferDescriptor mBufferInUse = null;
+ private CarEvsBufferDescriptor mBufferInUse;
- public GLES20CarEvsCameraPreviewRenderer(Context context,
- CarEvsCameraPreviewActivity activity) {
+ /** Load jni on initialization. */
+ static {
+ System.loadLibrary("carevsglrenderer_jni");
+ }
+
+ public GLES20CarEvsBufferRenderer(@NonNull Context context,
+ @NonNull CarEvsGLSurfaceView.BufferCallback callback, int angleInDegree) {
+
+ Preconditions.checkArgument(context != null, "Context cannot be null.");
+ Preconditions.checkArgument(callback != null, "Callback cannot be null.");
mContext = context;
- mActivity = activity;
+ mCallback = callback;
mVertCarPos = ByteBuffer.allocateDirect(sVertCarPosData.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mVertCarPos.put(sVertCarPosData).position(0);
- // Rotates the matrix in counter-clockwise
- int angleInDegree = mContext.getResources().getInteger(
- R.integer.config_evsRearviewCameraInPlaneRotationAngle);
double angleInRadian = Math.toRadians(angleInDegree);
float[] rotated = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
float sin = (float)Math.sin(angleInRadian);
@@ -140,7 +148,7 @@
}
// bufferToReturn is not null here.
- mActivity.returnBuffer(bufferToReturn);
+ mCallback.onBufferProcessed(bufferToReturn);
}
@Override
@@ -149,7 +157,8 @@
CarEvsBufferDescriptor bufferToRender = null;
CarEvsBufferDescriptor bufferToReturn = null;
- CarEvsBufferDescriptor newFrame = mActivity.getNewFrame();
+ CarEvsBufferDescriptor newFrame = mCallback.onBufferRequested();
+
synchronized (mLock) {
if (newFrame != null) {
// If a new frame has not been delivered yet, we're using a previous frame.
@@ -161,8 +170,15 @@
bufferToRender = mBufferInUse;
}
+ if (bufferToRender == null) {
+ if (DBG) {
+ Log.d(TAG, "No buffer to draw.");
+ }
+ return;
+ }
+
if (bufferToReturn != null) {
- mActivity.returnBuffer(bufferToReturn);
+ mCallback.onBufferProcessed(bufferToReturn);
}
// Specify a shader program to use
@@ -175,22 +191,13 @@
}
GLES20.glUniformMatrix4fv(matrix, 1, false, sIdentityMatrix, 0);
- if (bufferToRender == null) {
- // Show the default screen
- drawDefaultScreen();
- } else {
- // Retrieve a hardware buffer from a descriptor and update the texture
- HardwareBuffer buffer = bufferToRender.getHardwareBuffer();
- if (buffer == null) {
- Log.e(TAG, "HardwareBuffer is invalid.");
- drawDefaultScreen();
- } else {
- // Update the texture with a given hardware buffer
- if (!nUpdateTexture(buffer, mTextureId)) {
- throw new RuntimeException(
- "Failed to update the texture with the preview frame");
- }
- }
+ // Retrieve a hardware buffer from a descriptor and update the texture
+ HardwareBuffer buffer = bufferToRender.getHardwareBuffer();
+
+ // Update the texture with a given hardware buffer
+ if (!nUpdateTexture(buffer, mTextureId)) {
+ throw new RuntimeException(
+ "Failed to update the texture with the preview frame");
}
GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
@@ -239,7 +246,8 @@
mHeight = height;
}
- @Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+ @Override
+ public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
// Use the GLES20 class's static methods instead of a passed GL10 interface.
mProgram = buildShaderProgram(mVertexShader, mFragmentShader);
if (mProgram == 0) {
@@ -270,34 +278,6 @@
GLES20.GL_CLAMP_TO_EDGE);
}
- public void setTextLocation(float x, float y) {
- mTextX = x;
- mTextY = y;
- }
-
- private void drawDefaultScreen() {
- Drawable drawable = mContext.getResources().getDrawable(R.drawable.rearview);
- Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_4444);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, mWidth, mHeight);
- drawable.draw(canvas);
-
- Paint fontColor = new Paint();
- fontColor.setTextSize(Math.min(mWidth, mHeight) * 0.10f);
- fontColor.setAntiAlias(true);
-
- // Pick a font color randomly
- fontColor.setColor((0xFF << 24) + (mRandom.nextInt(0xFF) << 16)
- + (mRandom.nextInt(0xFF) << 8) + mRandom.nextInt(0xFF));
-
- // Set a location of the text relative to the surface size
- canvas.drawText("The rearview is not available.", mTextX, mTextY, fontColor);
-
- // Draw
- GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, /* level = */ 0, bitmap, /* border = */ 0);
- bitmap.recycle();
- }
-
private int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader == 0) {
@@ -342,6 +322,10 @@
checkGlError("glAttachShader");
GLES20.glAttachShader(program, fragmentShader);
checkGlError("glAttachShader");
+
+ GLES20.glBindAttribLocation(program, 0, "pos");
+ GLES20.glBindAttribLocation(program, 1, "tex");
+
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
@@ -363,21 +347,5 @@
}
}
- private Context mContext;
- private int mProgram;
- private int mTextureId;
- private FloatBuffer mVertCarPos;
- private FloatBuffer mVertCarTex;
- private int mWidth;
- private int mHeight;
- private float mTextX;
- private float mTextY;
- private Random mRandom = new Random();
-
- static {
- System.loadLibrary("carevsglrenderer_jni");
- }
-
- // Native method to update the texture with a received frame buffer
private native boolean nUpdateTexture(HardwareBuffer buffer, int textureId);
}
diff --git a/car-lib-module/api/current.txt b/car-lib-module/api/current.txt
index 05464e4..bae9a95 100644
--- a/car-lib-module/api/current.txt
+++ b/car-lib-module/api/current.txt
@@ -164,6 +164,7 @@
public static class CarVersion.VERSION_CODES {
field @NonNull public static final android.car.CarVersion TIRAMISU_0;
field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+ field @NonNull public static final android.car.CarVersion TIRAMISU_2;
}
@Deprecated public final class EvConnectorType {
@@ -214,6 +215,7 @@
public static class PlatformVersion.VERSION_CODES {
field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
}
public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 2ffe202..54792a8 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -1137,6 +1137,31 @@
}
+package android.car.oem {
+
+ public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+ method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+ }
+
+ public abstract class OemCarService extends android.app.Service {
+ ctor public OemCarService();
+ method @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+ method @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+ method @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method public abstract void onCarServiceReady();
+ method public final int onStartCommand(@Nullable android.content.Intent, int, int);
+ }
+
+ public interface OemCarServiceComponent {
+ method public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+ method public void init();
+ method public void onCarServiceReady();
+ method public void release();
+ }
+
+}
+
package android.car.os {
public final class CarPerformanceManager {
diff --git a/car-lib-module/api/test-current.txt b/car-lib-module/api/test-current.txt
index bcbc685..eeadc93 100644
--- a/car-lib-module/api/test-current.txt
+++ b/car-lib-module/api/test-current.txt
@@ -94,12 +94,14 @@
method public android.car.CarVersion get();
enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
}
public enum ApiRequirements.PlatformVersion {
method public android.car.PlatformVersion get();
enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
}
}
@@ -188,6 +190,7 @@
public final class CarTestManager {
ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
}
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 05464e4..bae9a95 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -164,6 +164,7 @@
public static class CarVersion.VERSION_CODES {
field @NonNull public static final android.car.CarVersion TIRAMISU_0;
field @NonNull public static final android.car.CarVersion TIRAMISU_1;
+ field @NonNull public static final android.car.CarVersion TIRAMISU_2;
}
@Deprecated public final class EvConnectorType {
@@ -214,6 +215,7 @@
public static class PlatformVersion.VERSION_CODES {
field @NonNull public static final android.car.PlatformVersion TIRAMISU_0;
field @NonNull public static final android.car.PlatformVersion TIRAMISU_1;
+ field @NonNull public static final android.car.PlatformVersion TIRAMISU_2;
}
public final class PlatformVersionMismatchException extends java.lang.UnsupportedOperationException implements android.os.Parcelable {
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 2ffe202..54792a8 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -1137,6 +1137,31 @@
}
+package android.car.oem {
+
+ public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+ method public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+ }
+
+ public abstract class OemCarService extends android.app.Service {
+ ctor public OemCarService();
+ method @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+ method @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+ method @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+ method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method public abstract void onCarServiceReady();
+ method public final int onStartCommand(@Nullable android.content.Intent, int, int);
+ }
+
+ public interface OemCarServiceComponent {
+ method public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+ method public void init();
+ method public void onCarServiceReady();
+ method public void release();
+ }
+
+}
+
package android.car.os {
public final class CarPerformanceManager {
diff --git a/car-lib/api/system-lint-baseline.txt b/car-lib/api/system-lint-baseline.txt
index cb1a48d..4aee850 100644
--- a/car-lib/api/system-lint-baseline.txt
+++ b/car-lib/api/system-lint-baseline.txt
@@ -65,6 +65,8 @@
Must override both equals and hashCode; missing one in android.car.vms.VmsAvailableLayers
+ExecutorRegistration: android.car.CarBugreportManager#requestBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.car.CarBugreportManager.CarBugreportManagerCallback):
+ Registration methods should have overload that accepts delivery Executor: `requestBugreport`
ExecutorRegistration: android.car.CarProjectionManager#registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int):
Registration methods should have overload that accepts delivery Executor: `registerProjectionListener`
ExecutorRegistration: android.car.CarProjectionManager#registerProjectionStatusListener(android.car.CarProjectionManager.ProjectionStatusListener):
@@ -75,6 +77,8 @@
Registration methods should have overload that accepts delivery Executor: `registerListener`
ExecutorRegistration: android.car.drivingstate.CarDrivingStateManager#registerListener(android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener):
Registration methods should have overload that accepts delivery Executor: `registerListener`
+ExecutorRegistration: android.car.drivingstate.CarUxRestrictionsManager#setListener(int, android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener):
+ Registration methods should have overload that accepts delivery Executor: `setListener`
ExecutorRegistration: android.car.hardware.CarVendorExtensionManager#registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback):
Registration methods should have overload that accepts delivery Executor: `registerCallback`
ExecutorRegistration: android.car.hardware.cabin.CarCabinManager#registerCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback):
@@ -643,8 +647,16 @@
Missing nullability on parameter `out` in method `writeToParcel`
+NotCloseable: android.car.oem.OemCarServiceComponent:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.car.oem.OemCarServiceComponent
+
+
NullableCollection: android.car.cluster.ClusterActivityState#getExtras():
Return type of method android.car.cluster.ClusterActivityState.getExtras() is a nullable collection (`android.os.Bundle`); must be non-null
+NullableCollection: android.car.drivingstate.CarUxRestrictionsManager#getConfigs():
+ Return type of method android.car.drivingstate.CarUxRestrictionsManager.getConfigs() is a nullable collection (`java.util.List`); must be non-null
+NullableCollection: android.car.drivingstate.CarUxRestrictionsManager#getStagedConfigs():
+ Return type of method android.car.drivingstate.CarUxRestrictionsManager.getStagedConfigs() is a nullable collection (`java.util.List`); must be non-null
NullableCollection: android.car.telemetry.CarTelemetryManager.MetricsReportCallback#onResult(String, android.os.PersistableBundle, byte[], int) parameter #1:
Type of parameter report in android.car.telemetry.CarTelemetryManager.MetricsReportCallback.onResult(String metricsConfigName, android.os.PersistableBundle report, byte[] telemetryError, int status) is a nullable collection (`android.os.PersistableBundle`); must be non-null
NullableCollection: android.car.watchdog.CarWatchdogManager#getResourceOveruseConfigurations(int):
@@ -677,6 +689,14 @@
If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.car.content.pm.CarAppBlockingPolicyService#getAppBlockingPolicy():
Methods implemented by developers should follow the on<Something> style, was `getAppBlockingPolicy`
+OnNameExpected: android.car.oem.OemCarService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.oem.OemCarService#getOemAudioFocusService():
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.car.oem.OemCarService#getSupportedCarVersion():
+ Methods implemented by developers should follow the on<Something> style, was `getSupportedCarVersion`
+OnNameExpected: android.car.oem.OemCarService#isOemServiceReady():
+ Methods implemented by developers should follow the on<Something> style, was `isOemServiceReady`
ParcelConstructor: android.car.content.pm.AppBlockingPackageInfo#AppBlockingPackageInfo(android.os.Parcel):
@@ -791,6 +811,12 @@
Builder must be final: android.car.hardware.CarPropertyConfig.Builder
+UseParcelFileDescriptor: android.car.oem.OemCarServiceComponent#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+ Must use ParcelFileDescriptor instead of FileDescriptor in parameter fd in android.car.oem.OemCarServiceComponent.dump(java.io.FileDescriptor fd, java.io.PrintWriter writer, String[] args)
+
+
+UserHandle: android.car.CarOccupantZoneManager#assignVisibleUserToOccupantZone(android.car.CarOccupantZoneManager.OccupantZoneInfo, android.os.UserHandle, int):
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.car.admin.CarDevicePolicyManager#removeUser(android.os.UserHandle):
When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.car.watchdog.CarWatchdogManager#getPackageKillableStatesAsUser(android.os.UserHandle):
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index 0923067..dd7151e 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -312,12 +312,14 @@
method public android.car.CarVersion get();
enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_0;
enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_1;
+ enum_constant public static final android.car.annotation.ApiRequirements.CarVersion TIRAMISU_2;
}
public enum ApiRequirements.PlatformVersion {
method public android.car.PlatformVersion get();
enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_0;
enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_1;
+ enum_constant public static final android.car.annotation.ApiRequirements.PlatformVersion TIRAMISU_2;
}
}
@@ -1203,6 +1205,31 @@
}
+package android.car.oem {
+
+ public interface OemCarAudioFocusService extends android.car.oem.OemCarServiceComponent {
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void audioFocusChanged(@NonNull java.util.List<android.media.AudioFocusInfo>, @NonNull java.util.List<android.media.AudioFocusInfo>, int);
+ }
+
+ public abstract class OemCarService extends android.app.Service {
+ ctor public OemCarService();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @CallSuper public void dump(@Nullable java.io.FileDescriptor, @Nullable java.io.PrintWriter, @Nullable String[]);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @Nullable public android.car.oem.OemCarAudioFocusService getOemAudioFocusService();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public abstract android.car.CarVersion getSupportedCarVersion();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public abstract void onCarServiceReady();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public final int onStartCommand(@Nullable android.content.Intent, int, int);
+ }
+
+ public interface OemCarServiceComponent {
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void dump(@Nullable java.io.PrintWriter, @Nullable String[]);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void init();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void onCarServiceReady();
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public void release();
+ }
+
+}
+
package android.car.os {
public final class CarPerformanceManager {
@@ -1467,6 +1494,7 @@
public final class CarTestManager {
ctor public CarTestManager(@NonNull android.car.Car, @NonNull android.os.IBinder);
+ method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_2, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public String getOemServiceName() throws android.os.RemoteException;
method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void startCarService(@NonNull android.os.IBinder);
method @RequiresPermission(android.car.Car.PERMISSION_CAR_TEST_SERVICE) public void stopCarService(@NonNull android.os.IBinder);
}
diff --git a/car-lib/src/android/car/CarVersion.java b/car-lib/src/android/car/CarVersion.java
index 8723bd3..712c104 100644
--- a/car-lib/src/android/car/CarVersion.java
+++ b/car-lib/src/android/car/CarVersion.java
@@ -54,6 +54,15 @@
public static final CarVersion TIRAMISU_1 =
new CarVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
+ /**
+ * Helper object for second minor upgrade of Android 13.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final CarVersion TIRAMISU_2 =
+ new CarVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
+
private VERSION_CODES() {
throw new UnsupportedOperationException("Only provide constants");
}
diff --git a/car-lib/src/android/car/PlatformVersion.java b/car-lib/src/android/car/PlatformVersion.java
index 6e360fe..9eea3a6 100644
--- a/car-lib/src/android/car/PlatformVersion.java
+++ b/car-lib/src/android/car/PlatformVersion.java
@@ -54,6 +54,15 @@
public static final PlatformVersion TIRAMISU_1 =
new PlatformVersion("TIRAMISU_1", Build.VERSION_CODES.TIRAMISU, 1);
+ /**
+ * Helper object for second minor upgrade of Android 13.
+ */
+ @ApiRequirements(minCarVersion = CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ @NonNull
+ public static final PlatformVersion TIRAMISU_2 =
+ new PlatformVersion("TIRAMISU_2", Build.VERSION_CODES.TIRAMISU, 2);
+
private VERSION_CODES() {
throw new UnsupportedOperationException("Only provide constants");
}
diff --git a/car-lib/src/android/car/annotation/ApiRequirements.java b/car-lib/src/android/car/annotation/ApiRequirements.java
index f5cfcda..1764ac6 100644
--- a/car-lib/src/android/car/annotation/ApiRequirements.java
+++ b/car-lib/src/android/car/annotation/ApiRequirements.java
@@ -57,7 +57,8 @@
enum CarVersion {
TIRAMISU_0(android.car.CarVersion.VERSION_CODES.TIRAMISU_0),
- TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1);
+ TIRAMISU_1(android.car.CarVersion.VERSION_CODES.TIRAMISU_1),
+ TIRAMISU_2(android.car.CarVersion.VERSION_CODES.TIRAMISU_2);
private final android.car.CarVersion mVersion;
@@ -77,7 +78,8 @@
enum PlatformVersion {
TIRAMISU_0(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_0),
- TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1);
+ TIRAMISU_1(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_1),
+ TIRAMISU_2(android.car.PlatformVersion.VERSION_CODES.TIRAMISU_2);
private final android.car.PlatformVersion mVersion;
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index 3320319..0ba250a 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -371,10 +371,10 @@
if (carPropertyEventCallbackController == null) {
return;
}
- boolean allCallbacksRemoved = carPropertyEventCallbackController.remove(
- carPropertyEventCallback);
- if (allCallbacksRemoved) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ boolean allCallbacksRemoved = carPropertyEventCallbackController.remove(
+ carPropertyEventCallback);
+ if (allCallbacksRemoved) {
mPropertyIdToCarPropertyEventCallbackController.remove(propertyId);
}
}
diff --git a/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
new file mode 100644
index 0000000..385b84d
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarAudioFocusService.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.media.AudioFocusInfo;
+
+/** @hide */
+interface IOemCarAudioFocusService {
+ void audioFocusChanged(in List<AudioFocusInfo> currentFocusHolders,
+ in List<AudioFocusInfo> currentFocusLosers, int zoneId);
+}
diff --git a/car-lib/src/android/car/oem/IOemCarService.aidl b/car-lib/src/android/car/oem/IOemCarService.aidl
new file mode 100644
index 0000000..ffc7125
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarService.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.car.CarVersion;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarServiceCallback;
+
+/*
+ * Binder for communicating with OEM Car Service.
+ */
+
+/** @hide */
+interface IOemCarService {
+ // Life cycle methods
+ /*
+ * Called when CarService is ready to take request. OemCarService is initialized before
+ * Car Service is ready. This signals OEM Service that CarService is ready.
+ * OemCarServiceCallback is passed from Car Service to OEM Service. One important call in the
+ * callback is sendOemCarServiceReady() which should be called to inform that OEM service is
+ * ready.
+ */
+ void onCarServiceReady(in IOemCarServiceCallback callback);
+
+ /*
+ * Gets the supported CarVersion for the OEM service. It is possible that CarModule is updated
+ * but OEM service is not updated. CarService needs to be aware of that.
+ */
+ CarVersion getSupportedCarVersion();
+
+ /*
+ * Gets the supported CarVersion for the OEM service. It is possible that CarModule is updated
+ * but OEM service is not updated. CarService needs to be aware of that.
+ */
+ String getAllStackTraces();
+
+ // Component services
+ IOemCarAudioFocusService getOemAudioFocusService();
+}
diff --git a/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl b/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl
new file mode 100644
index 0000000..13a0813
--- /dev/null
+++ b/car-lib/src/android/car/oem/IOemCarServiceCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.os.Bundle;
+
+/** @hide */
+interface IOemCarServiceCallback {
+ void sendOemCarServiceReady();
+}
\ No newline at end of file
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusService.java b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
new file mode 100644
index 0000000..2625c42
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+import android.media.AudioFocusInfo;
+
+import java.util.List;
+
+/*
+ * OemCarAudioFocusServiceInterface would expose all the method from IOemCarAudioFocusService. It
+ * should always be in sync with IOemCarAudioFocusService. Oem will implement
+ * OemCarAudioFocusServiceInterface which would be used by OemCarAudioFocusService.
+ */
+/**
+ * Interface for Audio focus for OEM Service.
+ *
+ * @hide
+ */
+@SystemApi
+public interface OemCarAudioFocusService extends OemCarServiceComponent {
+ /**
+ * Updates audio focus change. It is one way call for OEM Service.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+ @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId);
+}
diff --git a/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
new file mode 100644
index 0000000..0a1f0ee
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarAudioFocusServiceImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.annotation.NonNull;
+import android.car.annotation.ApiRequirements;
+import android.media.AudioFocusInfo;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * This code will be running as part of the OEM Service. This implements
+ * {@code IOemCarAudioFocusService} as hidden class. It is exposed as IBinder from {@link
+ * OemCarService#getOemAudioFocusService()}
+ *
+ * @hide
+ */
+final class OemCarAudioFocusServiceImpl extends IOemCarAudioFocusService.Stub
+ implements OemCarServiceComponent {
+
+ private final OemCarAudioFocusService mOemCarAudioFocusService;
+
+ OemCarAudioFocusServiceImpl(
+ @NonNull OemCarAudioFocusService oemCarAudioFocusService) {
+ mOemCarAudioFocusService = oemCarAudioFocusService;
+ }
+
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void audioFocusChanged(@NonNull List<AudioFocusInfo> currentFocusHolders,
+ @NonNull List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+ mOemCarAudioFocusService.audioFocusChanged(currentFocusHolders, currentFocusLosers,
+ zoneId);
+ }
+
+ @Override
+ public void init() {
+ mOemCarAudioFocusService.init();
+ }
+
+ @Override
+ public void release() {
+ mOemCarAudioFocusService.release();
+ }
+
+ @Override
+ public void dump(PrintWriter writer, String[] args) {
+ mOemCarAudioFocusService.dump(writer, args);
+ }
+
+ @Override
+ public void onCarServiceReady() {
+ mOemCarAudioFocusService.onCarServiceReady();
+ }
+}
diff --git a/car-lib/src/android/car/oem/OemCarService.java b/car-lib/src/android/car/oem/OemCarService.java
new file mode 100644
index 0000000..de62ab6
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarService.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.car.CarVersion;
+import android.car.annotation.ApiRequirements;
+import android.car.builtin.util.Slogf;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+
+/**
+ * This code will be running as part of the OEM Service. This provides basic implementation for OEM
+ * Service. OEMs should extend this class and override relevant methods.
+ *
+ * <p>
+ * OEM service implementation should have {@code android.car.permission.BIND_OEM_CAR_SERVICE} as
+ * required permission in manifest to connect to the OEM service.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class OemCarService extends Service {
+
+ private static final String TAG = OemCarService.class.getSimpleName();
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+ private static final String PERMISSION_BIND_OEM_CAR_SERVICE =
+ "android.car.permission.BIND_OEM_CAR_SERVICE";
+
+ // OEM Service components
+ // Note: Change the size as more components are added.
+ @GuardedBy("mLock")
+ private final ArrayMap<Class<?>, OemCarServiceComponent> mOemCarServiceComponents =
+ new ArrayMap<Class<?>, OemCarServiceComponent>(1);
+
+ private final Object mLock = new Object();
+
+ private final IOemCarService mInterface = new IOemCarService.Stub() {
+ // Component services
+ @Override
+ public IOemCarAudioFocusService getOemAudioFocusService() {
+ assertPermission();
+ synchronized (mLock) {
+ return (IOemCarAudioFocusService) mOemCarServiceComponents
+ .getOrDefault(IOemCarAudioFocusService.class, null);
+ }
+ }
+
+ @Override
+ public void onCarServiceReady(IOemCarServiceCallback callback) throws RemoteException {
+ assertPermission();
+ OemCarService.this.onCarServiceReady();
+ synchronized (mLock) {
+ for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+ if (DBG) {
+ Slogf.d(TAG, "Calling onCarServiceReady for %s\n",
+ mOemCarServiceComponents.keyAt(i).getSimpleName());
+ }
+ mOemCarServiceComponents.valueAt(i).onCarServiceReady();
+ }
+ }
+ callback.sendOemCarServiceReady();
+ }
+
+ @Override
+ public CarVersion getSupportedCarVersion() {
+ assertPermission();
+ return OemCarService.this.getSupportedCarVersion();
+ }
+
+ @Override
+ public String getAllStackTraces() {
+ assertPermission();
+ Map<Thread, StackTraceElement[]> tracesMap = Thread.getAllStackTraces();
+ StringBuilder sb = new StringBuilder();
+ sb.append("OemService stack trace:\n");
+ int i = 0;
+ for (Map.Entry<Thread, StackTraceElement[]> entry : tracesMap.entrySet()) {
+ sb.append("Thread: ").append(i++).append('\n');
+ StackTraceElement[] stack = entry.getValue();
+ for (int j = 0; j < stack.length; j++) {
+ sb.append(stack[j].toString()).append('\n');
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private void assertPermission() {
+ if (checkCallingPermission(
+ PERMISSION_BIND_OEM_CAR_SERVICE) != PackageManager.PERMISSION_GRANTED) {
+ String errorMsg = "Caller with uid:" + Binder.getCallingUid()
+ + " doesn't have permission " + PERMISSION_BIND_OEM_CAR_SERVICE;
+ Slogf.e(TAG, errorMsg);
+ throw new SecurityException(errorMsg);
+ }
+ }
+ };
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * OEM should override this method and do the initialization. OEM should also call super after
+ * initialization as this method would call {@link OemCarServiceComponent#init()} for each
+ * component implemented by OEM.
+ *
+ * <p>
+ * Car Service will not be available at the time of this initialization. If the OEM needs
+ * anything from CarService, they should wait for the CarServiceReady() call. It is expected
+ * that most of the initialization will finish in this call.
+ */
+ @Override
+ @CallSuper
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void onCreate() {
+ if (DBG) {
+ Slogf.d(TAG, "OnCreate");
+ }
+
+ // Create all components
+ OemCarAudioFocusService oemCarAudioFocusService = getOemAudioFocusService();
+ synchronized (mLock) {
+ if (oemCarAudioFocusService != null) {
+ mOemCarServiceComponents.put(IOemCarAudioFocusService.class,
+ new OemCarAudioFocusServiceImpl(oemCarAudioFocusService));
+ }
+
+ // Initialize them
+ for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+ if (DBG) {
+ Slogf.d(TAG, "Initializing %s\n",
+ mOemCarServiceComponents.keyAt(i).getSimpleName());
+ }
+ mOemCarServiceComponents.valueAt(i).init();
+ }
+ }
+ super.onCreate();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * OEM should override this method and do all the resources deallocation. OEM should also call
+ * super after resource deallocation as this method would call
+ * {@link OemCarServiceComponent#release()} for each component implemented by OEM.
+ */
+ @Override
+ @CallSuper
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void onDestroy() {
+ if (DBG) {
+ Slogf.d(TAG, "OnDestroy");
+ }
+
+ // Destroy all components and release the resources
+ synchronized (mLock) {
+ for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+ mOemCarServiceComponents.valueAt(i).release();
+ }
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public final int onStartCommand(@Nullable Intent intent, int flags, int startId) {
+ if (DBG) {
+ Slogf.d(TAG, "onStartCommand");
+ }
+ return START_STICKY;
+ }
+
+ @NonNull
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public final IBinder onBind(@Nullable Intent intent) {
+ if (DBG) {
+ Slogf.d(TAG, "onBind");
+ }
+ return mInterface.asBinder();
+ }
+
+ /**
+ * Gets Audio Focus Service implemented by OEM Service.
+ *
+ * @return audio focus service if implemented by OEM service, else return {@code null}.
+ */
+ @Nullable
+ @SuppressWarnings("[OnNameExpected]")
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public OemCarAudioFocusService getOemAudioFocusService() {
+ if (DBG) {
+ Slogf.d(TAG, "getOemUserService");
+ }
+ return null;
+ }
+
+ @CallSuper
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public void dump(@Nullable FileDescriptor fd, @Nullable PrintWriter writer,
+ @Nullable String[] args) {
+ writer.println("**** Dump OemCarService ****");
+ synchronized (mLock) {
+ for (int i = 0; i < mOemCarServiceComponents.size(); i++) {
+ mOemCarServiceComponents.valueAt(i).dump(writer, args);
+ }
+ }
+ }
+
+ /**
+ * Checks the supported CarVersion by the OEM service.
+ */
+ @SuppressWarnings("[OnNameExpected]")
+ @NonNull
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public abstract CarVersion getSupportedCarVersion();
+
+ /**
+ * Informs OEM service that CarService is now ready for communication.
+ *
+ * <p>
+ * OEM should override this method if there is any initialization depending on CarService.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public abstract void onCarServiceReady();
+}
diff --git a/car-lib/src/android/car/oem/OemCarServiceComponent.java b/car-lib/src/android/car/oem/OemCarServiceComponent.java
new file mode 100644
index 0000000..e0e5960
--- /dev/null
+++ b/car-lib/src/android/car/oem/OemCarServiceComponent.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.car.annotation.ApiRequirements;
+
+import java.io.PrintWriter;
+
+/**
+ * Contains life cycle methods for the OEM Service.
+ *
+ * <p>This is to enforce structure on the OEM Service components. {link OemCarService} would call
+ * these methods.
+ *
+ * @hide
+ */
+@SystemApi
+@SuppressWarnings("[NotCloseable]")
+public interface OemCarServiceComponent {
+ /**
+ * Initializes required resources.
+ *
+ * <p>This is called for each service component during {@link OemCarService#onCreate()}
+ * call of OemCarService.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ void init();
+
+ /**
+ * Releases required resources.
+ *
+ * <p>This is called for each service component during {@link OemCarService#onDestroy()}
+ * call of OemCarService.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ void release();
+
+ /**
+ * Dumps the service component details.
+ *
+ * <p>Each service component should implement a dump command to dump. It is called from
+ * {@link OemCarService#dump(java.io.FileDescriptor, PrintWriter, String[])} call.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ void dump(@Nullable PrintWriter writer, @Nullable String[] args);
+
+ /**
+ * Informs if CarService is ready.
+ *
+ * <p> Each service component should do the necessary initialization depending on CarService. It
+ * is called from {@link OemCarService#onCarServiceReady()} call.
+ */
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ void onCarServiceReady();
+}
diff --git a/car-lib/src/android/car/telemetry/telemetry.proto b/car-lib/src/android/car/telemetry/telemetry.proto
index 48b4c77..e384e83 100644
--- a/car-lib/src/android/car/telemetry/telemetry.proto
+++ b/car-lib/src/android/car/telemetry/telemetry.proto
@@ -84,6 +84,7 @@
// Collects all the app start events with the initial used RSS/CACHE/SWAP memory.
APP_START_MEMORY_STATE_CAPTURED = 1;
// Collects memory state of processes in 5-minute buckets (1 memory measurement per bucket).
+ // Consider using PROCESS_MEMORY_SNAPSHOT instead for smaller data size.
PROCESS_MEMORY_STATE = 2;
// Collects activity foreground/background transition events.
ACTIVITY_FOREGROUND_STATE_CHANGED = 3;
@@ -95,6 +96,10 @@
ANR_OCCURRED = 6;
// Collects "wtf"-level log events.
WTF_OCCURRED = 7;
+ // Collects memory snapshot of processes in 5-minute buckets (1 memory measurement per bucket).
+ // It differs from PROCESS_MEMORY_STATE in that the snapshot can be used for leaked memory
+ // detection by tracking anon RSS + swap usage.
+ PROCESS_MEMORY_SNAPSHOT = 8;
}
// Required.
@@ -127,12 +132,23 @@
optional OemType oem_type = 2;
}
-// Publisher for device-wide memory statistics.
-// It pulls data from /proc/meminfo every N seconds, where N is the read_interval_sec.
+// Publisher for device-wide memory statistics as well as process memory statistics.
+// It pulls data every N seconds, where N is the read_interval_sec.
+// Only one declaration of MemoryPublisher is allowed across all MetricsConfigs.
+// Performance on a device with 8GB RAM:
+// Collecting device meminfo takes 1-3ms.
+// Collecting process meminfo takes 70ms and up, depending on how many package names are specified.
+// For reference, collecting process memory on 1 process takes ~70ms, and for 10 processes it takes
+// ~200ms.
message MemoryPublisher {
// Required.
// The number of seconds in between each memory snapshot.
// The smallest acceptable read interval is 1, which means one snapshot per second.
+ // If only device meminfo is collected, i.e., leaving the package_names field as empty, then
+ // one snapshot per second is lightweight enough to be supported.
+ // However, collecting additional process meminfo is an expensive operation and has adverse
+ // system health impact. Client should consider increasing read_interval_sec to reduce the
+ // data collection frequency if package_names field is non-empty.
optional int32 read_interval_sec = 1;
// Optional.
@@ -145,6 +161,17 @@
// The maximum number of pending script execution tasks that the MemoryPublisher can produce
// before the publisher is throttled (rate-limited).
optional int32 max_pending_tasks = 3;
+
+ // Optional.
+ // The package names to get process memory statistics on. If specified, it will be published
+ // along with device memory.
+ // Important: Specifying package_names will increase the cost of data collection in
+ // MemoryPublisher. So it should be done carefully and only when necessary. Some remedies
+ // include increasing the read_interval_sec to reduce data collection frequency, and to use a
+ // small number for max_pending_tasks to throttle the publisher. Client should remove the
+ // MetricsConfig once enough process memory data has been collected. It is not intended to be
+ // used as continuous monitoring on process memory because it is an expensive call.
+ repeated string package_names = 4;
}
// Specifies data publisher and its parameters.
diff --git a/car-lib/src/android/car/test/CarTestManager.java b/car-lib/src/android/car/test/CarTestManager.java
index 41a0200..118317c 100644
--- a/car-lib/src/android/car/test/CarTestManager.java
+++ b/car-lib/src/android/car/test/CarTestManager.java
@@ -21,6 +21,7 @@
import android.car.Car;
import android.car.CarManagerBase;
import android.car.annotation.AddedInOrBefore;
+import android.car.annotation.ApiRequirements;
import android.os.IBinder;
import android.os.RemoteException;
@@ -90,4 +91,17 @@
handleRemoteExceptionFromCarService(e);
}
}
+
+ /**
+ * Returns OEM service name.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Car.PERMISSION_CAR_TEST_SERVICE)
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public String getOemServiceName() throws RemoteException {
+ return mService.getOemServiceName();
+ }
}
diff --git a/car-lib/src/android/car/test/ICarTest.aidl b/car-lib/src/android/car/test/ICarTest.aidl
index 90153cd..10388c8 100644
--- a/car-lib/src/android/car/test/ICarTest.aidl
+++ b/car-lib/src/android/car/test/ICarTest.aidl
@@ -31,4 +31,9 @@
/** Re initializes car services that was previously released by #releaseCarService method. */
void startCarService(IBinder token) = 2;
+
+ /**
+ * Returns OEM service name.
+ */
+ String getOemServiceName() = 3;
}
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
index 9be12ec..0bc17c1 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostManagementActivity.java
@@ -118,6 +118,7 @@
mHandlersList.setOnItemClickListener(mHandlerClickListener);
mController = new UsbHostController(this, new UsbCallbacks());
mPackageManager = getPackageManager();
+ hideDialog();
}
@Override
@@ -150,6 +151,21 @@
}
}
+ private void hideDialog() {
+ setTheme(android.R.style.Theme_Translucent);
+ if (mUsbHandlersDialog != null) {
+ mUsbHandlersDialog.setVisibility(View.GONE);
+ }
+ }
+
+ private void showDialog() {
+ setTranslucent(false);
+ setTheme(android.R.style.Theme_DeviceDefault_Dialog);
+ if (mUsbHandlersDialog != null) {
+ mUsbHandlersDialog.setVisibility(View.VISIBLE);
+ }
+ }
+
class UsbCallbacks implements UsbHostController.UsbHostControllerCallbacks {
private boolean mProcessing = false;
@@ -170,7 +186,7 @@
@Override
public void run() {
if (mProcessing && !mListAdapter.isEmpty()) {
- mUsbHandlersDialog.setVisibility(View.VISIBLE);
+ showDialog();
}
}
});
@@ -188,7 +204,7 @@
@Override
public void run() {
if (mProcessing) {
- mUsbHandlersDialog.setVisibility(View.VISIBLE);
+ showDialog();
}
mListAdapter.clear();
mListAdapter.addAll(options);
diff --git a/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml
new file mode 100644
index 0000000..8e1245a
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/color/car_ui_preference_primary_switch_background_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="false"
+ android:color="#202124"/>
+ <item android:color="?android:attr/colorAccent"
+ android:alpha="0.24"/>
+</selector>
\ No newline at end of file
diff --git a/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml
new file mode 100644
index 0000000..a537f00
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:gravity="center">
+ <shape android:shape="rectangle">
+ <corners android:radius="24dp" />
+ <solid android:color="@color/car_ui_preference_primary_switch_background_color" />
+ </shape>
+ </item>
+ <item android:drawable="@drawable/car_ui_preference_primary_switch_rotary_highlight" />
+</layer-list>
\ No newline at end of file
diff --git a/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
new file mode 100644
index 0000000..5cdde96
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright 2022 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="24dp" />
+ <solid android:color="#8A94CBFF" />
+ <stroke
+ android:width="4dp"
+ android:color="#94CBFF" />
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="24dp" />
+ <solid android:color="#3D94CBFF" />
+ <stroke
+ android:width="8dp"
+ android:color="#94CBFF" />
+ </shape>
+ </item>
+ <item>
+ <ripple android:color="?android:attr/colorControlHighlight" />
+ </item>
+</selector>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml
new file mode 100644
index 0000000..17325bd
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+-->
+
+<com.android.car.ui.uxr.DrawableStateRelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:tag="carUiPreference"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="16dp"
+ android:scaleType="fitCenter"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_toStartOf="@android:id/widget_frame"
+ android:orientation="vertical">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+ </LinearLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"/>
+
+</com.android.car.ui.uxr.DrawableStateRelativeLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml
new file mode 100644
index 0000000..717bf4d
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_category.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:focusable="true"
+ android:gravity="center_vertical"
+ android:minHeight="76dp"
+ android:orientation="horizontal"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="16dp"
+ android:scaleType="fitCenter"
+ android:tint="@color/car_ui_preference_icon_color"
+ tools:ignore="UseAppTint" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceCategoryTitle" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml
new file mode 100644
index 0000000..db9c216
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_footer.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+-->
+
+<com.android.car.ui.uxr.DrawableStateLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="left"
+ android:clipToPadding="false"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingBottom="16dp">
+
+ <com.android.car.ui.uxr.DrawableStateLinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:orientation="horizontal">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:padding="3dp"
+ android:alpha="72"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:textColor="@color/car_ui_text_color_secondary"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceCategoryTitle"/>
+ </com.android.car.ui.uxr.DrawableStateLinearLayout>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@+id/car_ui_link"
+ android:textColor="?android:attr/colorAccent"
+ android:textStyle="bold"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"/>
+</com.android.car.ui.uxr.DrawableStateLinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml
new file mode 100644
index 0000000..89b78ee
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_primary_switch.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+-->
+
+<com.android.car.ui.uxr.DrawableStateRelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/car_ui_preference_primary_switch_background"
+ android:clipToPadding="false"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:tag="carUiPreference"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+ <com.android.car.ui.uxr.DrawableStateImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginTop="16dp"
+ android:scaleType="fitCenter"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_toEndOf="@android:id/icon"
+ android:layout_toStartOf="@android:id/widget_frame"
+ android:orientation="vertical">
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+ </LinearLayout>
+
+ <!-- Preference should place its actual preference widget here. -->
+ <FrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"/>
+
+</com.android.car.ui.uxr.DrawableStateRelativeLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
index f32af91..f8a9e49 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_icon.xml
@@ -59,7 +59,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:singleLine="true"
+ android:maxLines="2"
+ android:ellipsize="end"
android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
<com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
index 1907b85..6f48698 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_switch.xml
@@ -59,7 +59,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:ellipsize="end"
+ android:maxLines="2"
android:textAlignment="viewStart"
android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle" />
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
index cde0c0f..3ef880f 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text.xml
@@ -59,7 +59,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:singleLine="true"
+ android:ellipsize="end"
+ android:maxLines="2"
android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
<com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
index 2084de2..5fdf3d6 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_two_action_text_borderless.xml
@@ -59,7 +59,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:singleLine="true"
+ android:ellipsize="end"
+ android:maxLines="2"
android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
<com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
index 9ff3564..54b9ebd 100644
--- a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_preference_widget_seekbar.xml
@@ -51,7 +51,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:ellipsize="end"
+ android:maxLines="2"
android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
<com.android.car.ui.uxr.DrawableStateTextView
diff --git a/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml
new file mode 100644
index 0000000..6f4d992
--- /dev/null
+++ b/car_product/app_overlays/car-ui-customizations/res/layout/car_ui_two_action_preference.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ <com.android.car.ui.uxr.DrawableStateLinearLayout
+ android:id="@+id/car_ui_preference_container_without_widget"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:clipToPadding="false"
+ android:gravity="start|center_vertical"
+ android:paddingBottom="16dp"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingTop="16dp">
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="44dp"
+ android:layout_height="44dp"
+ android:layout_marginEnd="16dp"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:orientation="vertical">
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+ <com.android.car.ui.uxr.DrawableStateTextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+ </LinearLayout>
+ </com.android.car.ui.uxr.DrawableStateLinearLayout>
+ <LinearLayout
+ android:id="@+id/action_widget_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:background="#75ffffff"/>
+ <!-- Preference should place its actual preference widget here. -->
+ <com.android.car.ui.uxr.DrawableStateFrameLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:minWidth="?android:attr/listPreferredItemHeightSmall"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/car_product/app_overlays/car-ui-customizations/res/values/colors.xml b/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
index 39bb196..e208ec7 100644
--- a/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/values/colors.xml
@@ -32,4 +32,6 @@
<color name="car_ui_seekbar_thumb">#FFFFFF</color>
<!-- The SeekBar thumb color when disabled. Use for the dark theme. -->
<color name="car_ui_seekbar_thumb_disabled_on_dark">#757575</color>
+ <!-- The preference category icon color-->
+ <color name="car_ui_preference_icon_color">@color/car_ui_text_color_primary</color>
</resources>
diff --git a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
index 85a6598..4bcbc1f 100644
--- a/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/app_overlays/car-ui-customizations/res/xml/overlays.xml
@@ -64,6 +64,9 @@
<item target="id/car_ui_second_action_container" value="@id/car_ui_second_action_container" />
<item target="id/car_ui_secondary_action" value="@id/car_ui_secondary_action" />
<item target="id/car_ui_secondary_action_concrete" value="@id/car_ui_secondary_action_concrete" />
+ <item target="id/car_ui_link" value="@id/car_ui_link" />
+ <item target="id/car_ui_preference_container_without_widget" value="@id/car_ui_preference_container_without_widget" />
+ <item target="id/action_widget_container" value="@id/action_widget_container" />
<item target="id/car_ui_toolbar_background" value="@id/car_ui_toolbar_background" />
<item target="id/car_ui_toolbar_logo" value="@id/car_ui_toolbar_logo" />
<item target="id/car_ui_toolbar_menu_item_icon_container" value="@id/car_ui_toolbar_menu_item_icon_container"/>
@@ -88,12 +91,17 @@
<item target="layout/car_ui_alert_dialog_list" value="@layout/car_ui_alert_dialog_list"/>
<item target="layout/car_ui_base_layout_toolbar" value="@layout/car_ui_base_layout_toolbar"/>
+ <item target="layout/car_ui_preference" value="@layout/car_ui_preference"/>
+ <item target="layout/car_ui_preference_category" value="@layout/car_ui_preference_category"/>
+ <item target="layout/car_ui_preference_footer" value="@layout/car_ui_preference_footer"/>
+ <item target="layout/car_ui_preference_primary_switch" value="@layout/car_ui_preference_primary_switch"/>
<item target="layout/car_ui_preference_two_action_icon" value="@layout/car_ui_preference_two_action_icon"/>
<item target="layout/car_ui_preference_two_action_switch" value="@layout/car_ui_preference_two_action_switch"/>
<item target="layout/car_ui_preference_two_action_text" value="@layout/car_ui_preference_two_action_text"/>
<item target="layout/car_ui_preference_two_action_text_borderless" value="@layout/car_ui_preference_two_action_text_borderless"/>
<item target="layout/car_ui_preference_widget_switch" value="@layout/car_ui_preference_widget_switch"/>
<item target="layout/car_ui_preference_widget_seekbar" value="@layout/car_ui_preference_widget_seekbar"/>
+ <item target="layout/car_ui_two_action_preference" value="@layout/car_ui_two_action_preference"/>
<item target="layout/car_ui_toolbar_menu_item_primary" value="@layout/car_ui_toolbar_menu_item_primary"/>
<item target="layout/car_ui_toolbar_menu_item" value="@layout/car_ui_toolbar_menu_item"/>
<item target="layout/car_ui_toolbar_two_row" value="@layout/car_ui_toolbar_two_row"/>
diff --git a/car_product/build/car.mk b/car_product/build/car.mk
index 7d5367c..cb25868 100644
--- a/car_product/build/car.mk
+++ b/car_product/build/car.mk
@@ -134,7 +134,7 @@
ro.android.car.carservice.package?=com.android.car.updatable
# Update with PLATFORM_VERSION_MINOR_INT update
-PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=1
+PRODUCT_SYSTEM_PROPERTIES += ro.android.car.version.platform_minor=2
# Automotive specific packages
PRODUCT_PACKAGES += \
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 8a8fff1..a7fcfde 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -354,6 +354,7 @@
</install-in-user-type>
<install-in-user-type package="com.android.permissioncontroller.car.rro">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.uwb.resources">
<install-in user-type="FULL" />
@@ -402,5 +403,6 @@
<install-in-user-type package="com.android.permissioncontroller">
<install-in user-type="FULL" />
<install-in user-type="SYSTEM" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
</config>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
index 43a611b..86742c3 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/res/values/config.xml
@@ -55,6 +55,7 @@
<item>com.google.android.car.setupwizard/.welcome.WelcomeActivity</item>
<item>com.google.android.car.setupwizard/.libs.uicommon.TrampolineActivity</item>
<item>com.google.android.apps.maps/com.google.android.apps.gmm.car.embedded.auxiliarymap.EmbeddedClusterActivity</item>
+ <item>com.android.mtp/com.android.mtp.ReceiverActivity</item>
</string-array>
<string name="config_controlBarActivity" translatable="false">
@@ -63,6 +64,9 @@
<string name="config_notificationCenterActivity" translatable="false">
com.android.car.notification/.CarNotificationCenterActivity
</string>
+ <string name="config_homeActivity" translatable="false">
+ com.android.car.carlauncher/.CarLauncher
+ </string>
<!-- default relaunch will be the first item -->
<string-array name="config_backgroundActivities" translatable="false">
<item>com.google.android.apps.maps/com.google.android.maps.MapsActivity</item>
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
index 038de27..a848f99 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaController.java
@@ -133,6 +133,7 @@
private final CarDisplayAreaOrganizer mOrganizer;
private final CarFullscreenTaskListener mCarFullscreenTaskListener;
private final ComponentName mControlBarActivityComponent;
+ private final ComponentName mHomeActivityComponent;
private final CarUiPortraitDisplaySystemBarsController mCarUiDisplaySystemBarsController;
private final CarDeviceProvisionedController mCarDeviceProvisionedController;
private final List<ComponentName> mBackgroundActivityComponent;
@@ -179,6 +180,7 @@
private boolean mIsForegroundAppRequestingImmersiveMode = false;
private boolean mIsUiModeNight = false;
private boolean mIsUserSetupInProgress;
+ private DisplayAreaComponent.FOREGROUND_DA_STATE mCurrentForegroundDaState;
// contains the list of activities that will be displayed on feature {@link
// CarDisplayAreaOrganizer.FEATURE_VOICE_PLATE)
private final Set<ComponentName> mVoicePlateActivitySet;
@@ -415,6 +417,8 @@
R.string.config_controlBarActivity));
mNotificationCenterComponent = ComponentName.unflattenFromString(resources.getString(
R.string.config_notificationCenterActivity));
+ mHomeActivityComponent = ComponentName.unflattenFromString(resources.getString(
+ R.string.config_homeActivity));
mBackgroundActivityComponent = new ArrayList<>();
mVoicePlateActivitySet = new ArraySet<>();
String[] backgroundActivities = mApplicationContext.getResources().getStringArray(
@@ -815,12 +819,20 @@
boolean isControlBar = componentName.equals(mControlBarActivityComponent);
boolean isBackgroundApp = mBackgroundActivityComponent.contains(componentName);
+ boolean isHomeActivity = componentName.equals(mHomeActivityComponent);
+
if (isBackgroundApp) {
// we don't want to change the state of the foreground DA when background
// apps are launched.
return;
}
+ if (isHomeActivity && (mCurrentForegroundDaState != CONTROL_BAR)) {
+ // close the foreground DA
+ startAnimation(CONTROL_BAR);
+ return;
+ }
+
if (isControlBar) {
// we don't want to change the state of the foreground DA when
// controlbar apps are launched.
@@ -844,10 +856,12 @@
// 3. for the current user ONLY. System user launches some tasks on cluster that should
// not affect the state of the foreground DA
// 4. any task that is manually defined to be ignored
+ // 5. home activity. We use this activity as the wallpaper.
if (!(taskInfo.displayAreaFeatureId == FEATURE_DEFAULT_TASK_CONTAINER
&& taskInfo.isVisible()
&& taskInfo.userId == ActivityManager.getCurrentUser()
- && !shouldIgnoreOpeningForegroundDA(taskInfo))) {
+ && !shouldIgnoreOpeningForegroundDA(taskInfo)
+ && !isHomeActivity)) {
return;
}
@@ -1002,6 +1016,7 @@
// TODO: currently the animations are only bottom/up. Make it more generic animations here.
int fromPos = 0;
int toPos = 0;
+ mCurrentForegroundDaState = toState;
switch (toState) {
case CONTROL_BAR:
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
index a883ed3..8eaad69 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/CarDisplayAreaOrganizer.java
@@ -26,6 +26,7 @@
import android.car.app.CarActivityManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
@@ -144,6 +145,12 @@
updateForegroundDisplayBounds(wct);
updateBackgroundDisplayBounds(wct);
}
+ else if (mToState == DisplayAreaComponent.FOREGROUND_DA_STATE.CONTROL_BAR) {
+ Intent homeActivityIntent = new Intent(Intent.ACTION_MAIN);
+ homeActivityIntent.addCategory(Intent.CATEGORY_HOME);
+ homeActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(homeActivityIntent);
+ }
}
}
diff --git a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
index d14287b..3d47945 100644
--- a/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
+++ b/car_product/car_ui_portrait/apps/CarUiPortraitSystemUI/src/com/android/systemui/car/displayarea/DisplayAreaComponent.java
@@ -34,7 +34,7 @@
* Dagger Subcomponent for DisplayAreas within SysUI.
*/
@SysUISingleton
-public class DisplayAreaComponent extends CoreStartable {
+public class DisplayAreaComponent implements CoreStartable {
public static final String TAG = "DisplayAreaComponent";
// action name for the intent when to update the foreground DA visibility
public static final String DISPLAY_AREA_VISIBILITY_CHANGED =
@@ -50,7 +50,6 @@
@Inject
public DisplayAreaComponent(Context context,
CarDisplayAreaController carDisplayAreaController) {
- super(context);
mContext = context;
mCarDisplayAreaController = carDisplayAreaController;
}
@@ -62,6 +61,23 @@
// Register the DA's
mCarDisplayAreaController.register();
+ IntentFilter filter = new IntentFilter();
+ // add a receiver to listen to ACTION_BOOT_COMPLETED where we will perform tasks that
+ // require system to be ready. For example, search list of activities with a specific
+ // Intent. This cannot be done while the component is created as that is too early in
+ // the lifecycle of system starting and the results returned by package manager is
+ // not reliable. So we want to wait until system is ready before we query for list of
+ // activities.
+ filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ mCarDisplayAreaController.updateVoicePlateActivityMap();
+ }
+ }
+ }, filter, /* broadcastPermission= */ null, /* scheduler= */ null);
+
IntentFilter packageChangeFilter = new IntentFilter();
// add a receiver to listen to ACTION_PACKAGE_ADDED to perform any action when a new
// application is installed on the system.
diff --git a/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml
new file mode 100644
index 0000000..0cb41cd
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/CarUiPortraitLauncherRRO/res/layout/car_launcher.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/colorBackground"
+ android:layoutDirection="ltr"
+ tools:context=".CarLauncher" />
+
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml
new file mode 100644
index 0000000..68c681c
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values-night/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<resources>
+ <!-- Specifies that the app theme has a dark background with light text on top -->
+ <bool name="car_ui_is_light_theme">false</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml
new file mode 100644
index 0000000..685d2e6
--- /dev/null
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/values/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<resources>
+ <!-- Specifies that the app theme has a light background with dark text on top -->
+ <bool name="car_ui_is_light_theme">true</bool>
+</resources>
diff --git a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
index 4ae10f2..1c53d75 100644
--- a/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
+++ b/car_product/car_ui_portrait/rro/car-ui-customizations/res/xml/overlays.xml
@@ -42,6 +42,7 @@
<item target="drawable/car_ui_toolbar_menu_item_divider" value="@drawable/car_ui_toolbar_menu_item_divider" />
<item target="drawable/car_ui_toolbar_menu_item_icon_ripple" value="@drawable/car_ui_toolbar_menu_item_icon_ripple" />
<item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable" />
+ <item target="bool/car_ui_is_light_theme" value="@bool/car_ui_is_light_theme" />
<item target="style/TextAppearance_CarUi_AlertDialog_Title" value="@style/TextAppearance_CarUi_AlertDialog_Title" />
<item target="style/TextAppearance_CarUi_AlertDialog_Subtitle" value="@style/TextAppearance_CarUi_AlertDialog_Subtitle" />
diff --git a/cpp/evs/manager/aidl/include/VirtualCamera.h b/cpp/evs/manager/aidl/include/VirtualCamera.h
index 04e64aa..2007215 100644
--- a/cpp/evs/manager/aidl/include/VirtualCamera.h
+++ b/cpp/evs/manager/aidl/include/VirtualCamera.h
@@ -27,6 +27,7 @@
#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
#include <aidl/android/hardware/automotive/evs/Stream.h>
+#include <android-base/thread_annotations.h>
#include <condition_variable>
#include <deque>
@@ -78,7 +79,10 @@
virtual ~VirtualCamera();
unsigned getAllowedBuffers() { return mFramesAllowed; };
- bool isStreaming() { return mStreamState == RUNNING; }
+ bool isStreaming() {
+ std::lock_guard lock(mMutex);
+ return mStreamState == RUNNING;
+ }
std::vector<std::shared_ptr<HalCamera>> getHalCameras();
void setDescriptor(aidlevs::CameraDesc* desc) { mDesc = desc; }
@@ -87,7 +91,7 @@
bool deliverFrame(const aidlevs::BufferDesc& bufDesc);
// Dump current status to a given file descriptor
- std::string toString(const char* indent = "") const;
+ std::string toString(const char* indent = "") const NO_THREAD_SAFETY_ANALYSIS;
private:
void shutdown();
@@ -104,7 +108,7 @@
STOPPED,
RUNNING,
STOPPING,
- } mStreamState = STOPPED;
+ } mStreamState GUARDED_BY(mMutex) = STOPPED;
std::unordered_map<std::string, std::deque<aidlevs::BufferDesc>> mFramesHeld;
std::thread mCaptureThread;
diff --git a/cpp/evs/manager/aidl/src/VirtualCamera.cpp b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
index e1b2968..7aa6dd1 100644
--- a/cpp/evs/manager/aidl/src/VirtualCamera.cpp
+++ b/cpp/evs/manager/aidl/src/VirtualCamera.cpp
@@ -463,8 +463,16 @@
constexpr auto kFrameTimeout = 5s; // timeout in seconds.
int64_t lastFrameTimestamp = -1;
EvsResult status = EvsResult::OK;
- while (mStreamState == RUNNING) {
+ while (true) {
std::unique_lock lock(mMutex);
+ ::android::base::ScopedLockAssertion assume_lock(mMutex);
+
+ if (mStreamState != RUNNING) {
+ // A video stream is stopped while a capture thread is acquiring
+ // a lock.
+ LOG(DEBUG) << "Requested to stop capturing frames";
+ break;
+ }
unsigned count = 0;
for (auto&& [key, hwCamera] : mHalCamera) {
@@ -485,7 +493,7 @@
break;
}
- if (!mFramesReadySignal.wait_for(lock, kFrameTimeout, [this]() {
+ if (!mFramesReadySignal.wait_for(lock, kFrameTimeout, [this]() REQUIRES(mMutex) {
// Stops waiting if
// 1) we've requested to stop capturing
// new frames
@@ -498,35 +506,43 @@
LOG(DEBUG) << "Timer for a new frame expires";
status = EvsResult::UNDERLYING_SERVICE_ERROR;
break;
- } else if (mStreamState == RUNNING) {
- // Fetch frames and forward to the client
- if (!mFramesHeld.empty() && mStream) {
- // Pass this buffer through to our client
- std::vector<BufferDesc> frames;
- frames.resize(count);
- unsigned i = 0;
- for (auto&& [key, hwCamera] : mHalCamera) {
- std::shared_ptr<HalCamera> pHwCamera = hwCamera.lock();
- if (!pHwCamera || mFramesHeld[key].empty()) {
- continue;
- }
+ }
- // Duplicate the latest buffer and forward it to the
- // active clients
- auto frame = Utils::dupBufferDesc(mFramesHeld[key].back(),
- /* doDup= */ true);
- if (frame.timestamp > lastFrameTimestamp) {
- lastFrameTimestamp = frame.timestamp;
- }
- frames[i++] = std::move(frame);
- }
+ if (mStreamState != RUNNING || !mStream) {
+ // A video stream is stopped while a capture thread is waiting
+ // for a new frame or we have lost a client.
+ LOG(DEBUG) << "Requested to stop capturing frames or lost a client";
+ break;
+ }
- if (!mStream->deliverFrame(frames).isOk()) {
- LOG(WARNING) << "Failed to forward frames";
- }
+ // Fetch frames and forward to the client
+ if (mFramesHeld.empty()) {
+ // We do not have any frame to forward.
+ continue;
+ }
+
+ // Pass this buffer through to our client
+ std::vector<BufferDesc> frames;
+ frames.resize(count);
+ unsigned i = 0;
+ for (auto&& [key, hwCamera] : mHalCamera) {
+ std::shared_ptr<HalCamera> pHwCamera = hwCamera.lock();
+ if (!pHwCamera || mFramesHeld[key].empty()) {
+ continue;
}
- } else if (mStreamState != RUNNING) {
- LOG(DEBUG) << "Requested to stop capturing frames";
+
+ // Duplicate the latest buffer and forward it to the
+ // active clients
+ auto frame = Utils::dupBufferDesc(mFramesHeld[key].back(),
+ /* doDup= */ true);
+ if (frame.timestamp > lastFrameTimestamp) {
+ lastFrameTimestamp = frame.timestamp;
+ }
+ frames[i++] = std::move(frame);
+ }
+
+ if (!mStream->deliverFrame(frames).isOk()) {
+ LOG(WARNING) << "Failed to forward frames";
}
}
@@ -554,6 +570,10 @@
ScopedAStatus VirtualCamera::stopVideoStream() {
{
std::lock_guard lock(mMutex);
+ if (mStreamState != RUNNING) {
+ // No action is required.
+ return ScopedAStatus::ok();
+ }
if (!mStream || mStreamState != RUNNING) {
// Safely ignore a request to stop video stream
@@ -570,7 +590,7 @@
EvsEventDesc event{
.aType = EvsEventType::STREAM_STOPPED,
};
- if (!mStream->notify(std::move(event)).isOk()) {
+ if (mStream && !mStream->notify(std::move(event)).isOk()) {
LOG(WARNING) << "Error delivering end of stream event";
}
@@ -579,20 +599,20 @@
// Note, however, that there still might be frames already queued that client will see
// after returning from the client side of this call.
mStreamState = STOPPED;
-
- // Give the underlying hardware camera the heads up that it might be time to stop
- for (auto&& [_, hwCamera] : mHalCamera) {
- auto pHwCamera = hwCamera.lock();
- if (pHwCamera) {
- pHwCamera->clientStreamEnding(this);
- }
- }
-
- // Signal a condition to unblock a capture thread and then join
- mSourceCameras.clear();
- mFramesReadySignal.notify_all();
}
+ // Give the underlying hardware camera the heads up that it might be time to stop
+ for (auto&& [_, hwCamera] : mHalCamera) {
+ auto pHwCamera = hwCamera.lock();
+ if (pHwCamera) {
+ pHwCamera->clientStreamEnding(this);
+ }
+ }
+
+ // Signal a condition to unblock a capture thread and then join
+ mSourceCameras.clear();
+ mFramesReadySignal.notify_all();
+
if (mCaptureThread.joinable()) {
mCaptureThread.join();
}
@@ -740,18 +760,23 @@
bool VirtualCamera::notify(const EvsEventDesc& event) {
switch (event.aType) {
- case EvsEventType::STREAM_STOPPED:
- if (mStreamState != STOPPING) {
+ case EvsEventType::STREAM_STOPPED: {
+ {
+ std::lock_guard lock(mMutex);
+ if (mStreamState != RUNNING) {
+ // We're not actively consuming a video stream or already in
+ // a process to stop a video stream.
+ return true;
+ }
+
// Warn if we got an unexpected stream termination
LOG(WARNING) << "Stream unexpectedly stopped, current status " << mStreamState;
-
- // Clean up the resource and forward an event to the client
- stopVideoStream();
-
- // This event is handled properly.
- return true;
}
- break;
+
+ // Clean up the resource and forward an event to the client
+ stopVideoStream();
+ return true;
+ }
// v1.0 client will ignore all other events.
case EvsEventType::PARAMETER_CHANGED:
diff --git a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
index 049b68c..c6746af 100644
--- a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
+++ b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
@@ -237,7 +237,7 @@
mSilentModeHandler(this),
mIsPowerPolicyLocked(false),
mIsCarServiceInOperation(false),
- mIsFirstConnectionToVhal(false) {
+ mIsFirstConnectionToVhal(true) {
mMessageHandler = new MessageHandlerImpl(this);
mDeathRecipient = ScopedAIBinder_DeathRecipient(
AIBinder_DeathRecipient_new(&CarPowerPolicyServer::onBinderDied));
@@ -713,6 +713,7 @@
!ret.ok()) {
ALOGW("Cannot apply the initial power policy(%s): %s", policyId.c_str(),
ret.error().message().c_str());
+ return;
}
ALOGD("Policy(%s) is applied as the initial one", policyId.c_str());
}
diff --git a/cpp/powerpolicy/server/src/PolicyManager.cpp b/cpp/powerpolicy/server/src/PolicyManager.cpp
index 33a8f80..6100056 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.cpp
+++ b/cpp/powerpolicy/server/src/PolicyManager.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "carpowerpolicyd"
+#define DEBUG false // STOPSHIP if true.
#include "PolicyManager.h"
@@ -66,6 +67,7 @@
constexpr const char kAttrBehavior[] = "behavior";
constexpr const char kAttrId[] = "id";
constexpr const char kAttrState[] = "state";
+constexpr const char kAttrDefaultPolicyGroup[] = "defaultPolicyGroup";
// Power states.
constexpr const char kPowerStateOn[] = "on";
@@ -324,14 +326,27 @@
return policyGroup;
}
-Result<std::unordered_map<std::string, PolicyGroup>> readPolicyGroups(
+struct PolicyGroups {
+ std::unordered_map<std::string, PolicyGroup> groups;
+ std::string defaultGroup;
+};
+
+Result<PolicyGroups> readPolicyGroups(
const XMLElement* pRoot,
const std::unordered_map<std::string, CarPowerPolicyPtr>& registeredPowerPolicies) {
const XMLElement* pPolicyGroups = pRoot->FirstChildElement(kTagPolicyGroups);
+
+ PolicyGroups policyGroups;
+
if (pPolicyGroups == nullptr) {
- return std::unordered_map<std::string, PolicyGroup>();
+ return policyGroups;
}
- std::unordered_map<std::string, PolicyGroup> policyGroups;
+
+ const char* pDefaultPolicyGroupId = nullptr;
+ pPolicyGroups->QueryStringAttribute(kAttrDefaultPolicyGroup, &pDefaultPolicyGroupId);
+ if (pDefaultPolicyGroupId != nullptr) {
+ policyGroups.defaultGroup = pDefaultPolicyGroupId;
+ }
for (const XMLElement* pPolicyGroup = pPolicyGroups->FirstChildElement(kTagPolicyGroup);
pPolicyGroup != nullptr;
@@ -345,7 +360,7 @@
if (!policyGroup.ok()) {
return Error() << policyGroup.error();
}
- policyGroups.emplace(policyGroupId, *policyGroup);
+ policyGroups.groups.emplace(policyGroupId, *policyGroup);
}
return policyGroups;
}
@@ -475,10 +490,13 @@
Result<CarPowerPolicyPtr> PolicyManager::getDefaultPowerPolicyForState(
const std::string& groupId, VehicleApPowerStateReport state) const {
- if (mPolicyGroups.count(groupId) == 0) {
- return Error() << StringPrintf("Power policy group(%s) is not available", groupId.c_str());
+ auto groupIdToUse = groupId.empty() ? mDefaultPolicyGroup : groupId;
+
+ if (mPolicyGroups.count(groupIdToUse) == 0) {
+ return Error() << StringPrintf("Power policy group %s is not found", groupIdToUse.c_str());
}
- PolicyGroup policyGroup = mPolicyGroups.at(groupId);
+
+ PolicyGroup policyGroup = mPolicyGroups.at(groupIdToUse);
int32_t key = static_cast<int32_t>(state);
if (policyGroup.count(key) == 0) {
return Error() << StringPrintf("Policy for %s is not found", toString(state).c_str());
@@ -572,6 +590,7 @@
for (auto policy : *registeredPolicies) {
registeredPoliciesMap.emplace(policy->policyId, policy);
}
+
const auto& policyGroups = readPolicyGroups(pRootElement, registeredPoliciesMap);
if (!policyGroups.ok()) {
logXmlError(StringPrintf("Reading power policy groups for power state failed: %s",
@@ -587,7 +606,8 @@
mRegisteredPowerPolicies = registeredPoliciesMap;
initRegularPowerPolicy(/*override=*/false);
- mPolicyGroups = *policyGroups;
+ mPolicyGroups = policyGroups->groups;
+ mDefaultPolicyGroup = policyGroups->defaultGroup;
reconstructNoUserInteractionPolicy(*systemPolicyOverrides);
}
@@ -633,6 +653,10 @@
kSuspendPrepDisabledComponents));
}
+std::string PolicyManager::getDefaultPolicyGroup() const {
+ return mDefaultPolicyGroup;
+}
+
} // namespace powerpolicy
} // namespace automotive
} // namespace frameworks
diff --git a/cpp/powerpolicy/server/src/PolicyManager.h b/cpp/powerpolicy/server/src/PolicyManager.h
index 7c1e7fa..fe5ed50 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.h
+++ b/cpp/powerpolicy/server/src/PolicyManager.h
@@ -48,7 +48,7 @@
constexpr const char kSystemPolicyIdNoUserInteraction[] = "system_power_policy_no_user_interaction";
constexpr const char kSystemPolicyIdAllOn[] = "system_power_policy_all_on";
-constexpr const char kSystemPolicyIdInitialOn[] = "system_power_policy_initiall_on";
+constexpr const char kSystemPolicyIdInitialOn[] = "system_power_policy_initial_on";
constexpr const char kSystemPolicyIdSuspendPrep[] = "system_power_policy_suspend_prep";
// Forward declaration for testing use only.
@@ -83,6 +83,7 @@
const std::string& policyId, const std::vector<std::string>& enabledComponents,
const std::vector<std::string>& disabledComponents);
android::base::Result<void> dump(int fd, const android::Vector<String16>& args);
+ std::string getDefaultPolicyGroup() const;
private:
void initRegularPowerPolicy(bool override);
@@ -95,6 +96,7 @@
std::unordered_map<std::string, CarPowerPolicyPtr> mRegisteredPowerPolicies;
std::unordered_map<std::string, CarPowerPolicyPtr> mPreemptivePowerPolicies;
std::unordered_map<std::string, PolicyGroup> mPolicyGroups;
+ std::string mDefaultPolicyGroup;
// For unit tests.
friend class internal::PolicyManagerPeer;
diff --git a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
index 40837df..ad61627 100644
--- a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
+++ b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
@@ -33,7 +33,7 @@
using ::tinyxml2::XML_SUCCESS;
using ::tinyxml2::XMLDocument;
-namespace {
+namespace test {
constexpr const char* kDirPrefix = "/tests/data/";
@@ -46,10 +46,15 @@
"valid_power_policy_policies_only.xml";
constexpr const char* kValidPowerPolicySystemPowerPolicyOnlyXmlFile =
"valid_power_policy_system_power_policy_only.xml";
+constexpr const char* kValidPowerPolicyWithDefaultPolicyGroup =
+ "valid_power_policy_default_policy_group.xml";
+constexpr const char* kValidPowerPolicyWithInvalidDefaultPolicyGroup =
+ "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml";
const std::vector<const char*> kInvalidPowerPolicyXmlFiles =
{"invalid_power_policy_incorrect_id.xml",
"invalid_power_policy_incorrect_othercomponent.xml",
- "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml"};
+ "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml",
+ "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml"};
const std::vector<const char*> kInvalidPowerPolicyGroupXmlFiles =
{"invalid_power_policy_group_incorrect_state.xml",
"invalid_power_policy_group_missing_policy.xml"};
@@ -69,6 +74,7 @@
constexpr const char* kSystemPolicyIdInitialOn = "system_power_policy_initial_on";
constexpr const char* kSystemPolicyIdInitialAllOn = "system_power_policy_all_on";
constexpr const char* kSystemPolicyIdSuspendPrep = "system_power_policy_suspend_prep";
+constexpr const char* kMixedPolicyGroupName = "mixed_policy_group";
const VehicleApPowerStateReport kExistingTransition = VehicleApPowerStateReport::WAIT_FOR_VHAL;
const VehicleApPowerStateReport kNonExistingTransition = static_cast<VehicleApPowerStateReport>(-1);
@@ -227,7 +233,7 @@
ASSERT_TRUE(policyManager.getPowerPolicy(kSystemPolicyIdInitialAllOn).ok());
}
-} // namespace
+} // namespace test
namespace internal {
@@ -244,7 +250,7 @@
private:
void readXmlFile(const char* filename) {
XMLDocument xmlDoc;
- std::string path = getTestDataPath(filename);
+ std::string path = test::getTestDataPath(filename);
xmlDoc.LoadFile(path.c_str());
ASSERT_TRUE(xmlDoc.ErrorID() == XML_SUCCESS);
mManager->readPowerPolicyFromXml(xmlDoc);
@@ -256,6 +262,8 @@
} // namespace internal
+namespace test {
+
class PolicyManagerTest : public ::testing::Test {};
TEST_F(PolicyManagerTest, TestValidXml_PowerPolicy) {
@@ -344,6 +352,27 @@
checkSystemPowerPolicy(policyManager, kModifiedSystemPowerPolicy);
}
+TEST_F(PolicyManagerTest, TestValidXml_TestDefaultPowerPolicyGroupId) {
+ PolicyManager policyManager;
+ internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+ policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithDefaultPolicyGroup);
+
+ ASSERT_TRUE(policyManager.getDefaultPolicyGroup() == kMixedPolicyGroupName);
+}
+
+TEST_F(PolicyManagerTest, TestValidXml_TestInvalidDefaultPowerPolicyGroupId) {
+ PolicyManager policyManager;
+ internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+ policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithInvalidDefaultPolicyGroup);
+
+ ASSERT_EQ(policyManager.getDefaultPolicyGroup(), "");
+
+ ASSERT_FALSE(
+ policyManager
+ .getDefaultPowerPolicyForState(kInvalidPowerPolicyGroupId, kExistingTransition)
+ .ok());
+}
+
TEST_F(PolicyManagerTest, TestDefaultPowerPolicies) {
PolicyManager policyManager;
internal::PolicyManagerPeer policyManagerPeer(&policyManager);
@@ -419,6 +448,7 @@
ASSERT_TRUE(systemPolicyDefault->disabledComponents.empty());
}
+} // namespace test
} // namespace powerpolicy
} // namespace automotive
} // namespace frameworks
diff --git a/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..4c1b161
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<powerPolicy version="1.0">
+
+ <policyGroups defaultPolicyGroup="someGroup">
+ <policyGroup id="mixed_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+ </policyGroup>
+ </policyGroups>
+
+ <policies>
+ <policy id="expected_to_be_registered">
+ <otherComponents behavior="on"/>
+ </policy>
+ </policies>
+
+ <systemPolicyOverrides>
+ <policy id="system_power_policy_incorrect_id">
+ <component id="POWER_COMPONENT_NFC">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..89d1508
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<powerPolicy version="1.0">
+
+ <policyGroups defaultPolicyGroup="mixed_policy_group">
+ <policyGroup id="basic_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+ <defaultPolicy state="On" id="policy_id_other_untouched"/>
+ </policyGroup>
+ <policyGroup id="no_default_policy_group">
+ <noDefaultPolicy state="WaitForVHAL"/>
+ <noDefaultPolicy state="On"/>
+ </policyGroup>
+ <policyGroup id="mixed_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+ <noDefaultPolicy state="On"/>
+ </policyGroup>
+ </policyGroups>
+
+ <policies>
+ <policy id="expected_to_be_registered">
+ <otherComponents behavior="on"/>
+ </policy>
+ <policy id="policy_id_other_off">
+ <otherComponents behavior="off"/>
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_DISPLAY">off</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ <policy id="policy_id_other_untouched">
+ <otherComponents behavior="untouched"/>
+ <component id="POWER_COMPONENT_AUDIO">on</component>
+ <component id="POWER_COMPONENT_DISPLAY">on</component>
+ <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+ </policy>
+ <policy id="policy_id_other_on">
+ <otherComponents behavior="on"/>
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ <policy id="policy_id_other_none">
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </policies>
+
+ <systemPolicyOverrides>
+ <policy id="system_power_policy_no_user_interaction">
+ <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+ <component id="POWER_COMPONENT_NFC">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
index 4e0ace2..a26b93f 100644
--- a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog.internal/current/android/automotive/watchdog/internal/PowerCycle.aidl
@@ -37,5 +37,9 @@
POWER_CYCLE_SHUTDOWN_PREPARE = 0,
POWER_CYCLE_SHUTDOWN_ENTER = 1,
POWER_CYCLE_RESUME = 2,
+ /**
+ * @deprecated Value of enum no longer reflects the true amount of power cycles. Enum should not be used.
+ */
NUM_POWER_CYLES = 3,
+ POWER_CYCLE_SUSPEND_EXIT = 4,
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
index a23fa4e..a2e53c2 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PowerCycle.aidl
@@ -38,6 +38,14 @@
/**
* Number of available power cycles.
+ *
+ * @deprecated Value of enum no longer reflects the true amount of power cycles.
+ * Enum should not be used.
*/
NUM_POWER_CYLES,
+
+ /**
+ * The system wakes up from deep sleep or hibernation.
+ */
+ POWER_CYCLE_SUSPEND_EXIT,
}
diff --git a/cpp/watchdog/sepolicy/public/carwatchdog.te b/cpp/watchdog/sepolicy/public/carwatchdog.te
index fd7ab3b..fa40f68 100644
--- a/cpp/watchdog/sepolicy/public/carwatchdog.te
+++ b/cpp/watchdog/sepolicy/public/carwatchdog.te
@@ -7,3 +7,5 @@
# Configuration for system_server.
allow system_server carwatchdogd_service:service_manager find;
binder_call(carwatchdogd, system_server)
+
+allow carwatchdogd servicemanager:service_manager list;
diff --git a/cpp/watchdog/server/carwatchdogd.rc b/cpp/watchdog/server/carwatchdogd.rc
index 1fd121b..6184541 100644
--- a/cpp/watchdog/server/carwatchdogd.rc
+++ b/cpp/watchdog/server/carwatchdogd.rc
@@ -28,6 +28,7 @@
# Below durations are in seconds
setprop ro.carwatchdog.post_system_event_duration 30
setprop ro.carwatchdog.user_switch_timeout 30
+ setprop ro.carwatchdog.wake_up_event_duration 30
on early-init && property:ro.build.type=eng
# Below intervals are in seconds
@@ -38,6 +39,7 @@
# Below durations are in seconds
setprop ro.carwatchdog.post_system_event_duration 30
setprop ro.carwatchdog.user_switch_timeout 30
+ setprop ro.carwatchdog.wake_up_event_duration 30
on early-init && property:ro.build.type=user
# Below intervals are in seconds
@@ -48,6 +50,7 @@
# Below durations are in seconds
setprop ro.carwatchdog.post_system_event_duration 30
setprop ro.carwatchdog.user_switch_timeout 30
+ setprop ro.carwatchdog.wake_up_event_duration 30
on init
# Number of top stats per category
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index 3a858a8..71fd002 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -113,6 +113,12 @@
// Below methods implement DataProcessorInterface.
std::string name() const override { return "IoOveruseMonitor"; }
friend std::ostream& operator<<(std::ostream& os, const IoOveruseMonitor& monitor);
+
+ android::base::Result<void> onSystemStartup() {
+ // No tracking of boot-time and wake-up events in I/O overuse monitoring.
+ return {};
+ }
+
android::base::Result<void> onBoottimeCollection(
[[maybe_unused]] time_t time,
[[maybe_unused]] const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -122,6 +128,15 @@
return {};
}
+ android::base::Result<void> onWakeUpCollection(
+ [[maybe_unused]] time_t time,
+ [[maybe_unused]] const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ [[maybe_unused]] const android::wp<ProcStatCollectorInterface>& procStatCollector)
+ override {
+ // No I/O overuse monitoring during wake up.
+ return {};
+ }
+
android::base::Result<void> onUserSwitchCollection(
[[maybe_unused]] time_t time, [[maybe_unused]] userid_t from,
[[maybe_unused]] userid_t to,
diff --git a/cpp/watchdog/server/src/IoPerfCollection.cpp b/cpp/watchdog/server/src/IoPerfCollection.cpp
index a7e26ca..ee333e7 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.cpp
+++ b/cpp/watchdog/server/src/IoPerfCollection.cpp
@@ -53,6 +53,7 @@
constexpr const char kUserSwitchCollectionTitle[] =
"%s\nUser-switch events performance report:\n%s\n";
constexpr const char kUserSwitchCollectionSubtitle[] = "Number of user switch events: %zu\n";
+constexpr const char kWakeUpCollectionTitle[] = "%s\nWake-up performance report:\n%s\n";
constexpr const char kCustomCollectionTitle[] = "%s\nCustom performance data report:\n%s\n";
constexpr const char kUserSwitchEventTitle[] = "\nEvent %zu: From: %d To: %d\n%s\n";
constexpr const char kCollectionTitle[] =
@@ -368,6 +369,10 @@
.maxCacheSize = periodicCollectionBufferSize,
.records = {},
};
+ mWakeUpCollection = {
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {},
+ };
mCustomCollection = {
.maxCacheSize = std::numeric_limits<std::size_t>::max(),
.records = {},
@@ -400,6 +405,12 @@
!WriteStringToFd(mBoottimeCollection.toString(), fd)) {
return Error(FAILED_TRANSACTION) << "Failed to dump the boot-time collection report.";
}
+ if (!WriteStringToFd(StringPrintf(kWakeUpCollectionTitle, std::string(75, '-').c_str(),
+ std::string(27, '=').c_str()),
+ fd) ||
+ !WriteStringToFd(mWakeUpCollection.toString(), fd)) {
+ return Error(FAILED_TRANSACTION) << "Failed to dump the wake-up collection report.";
+ }
if (const auto& result = onUserSwitchCollectionDump(fd); !result.ok()) {
return result.error();
}
@@ -433,6 +444,13 @@
return {};
}
+Result<void> IoPerfCollection::onSystemStartup() {
+ Mutex::Autolock lock(mMutex);
+ mBoottimeCollection.records.clear();
+ mWakeUpCollection.records.clear();
+ return {};
+}
+
Result<void> IoPerfCollection::onBoottimeCollection(
time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
const wp<ProcStatCollectorInterface>& procStatCollector) {
@@ -492,6 +510,20 @@
procStatCollectorSp, &mUserSwitchCollections.back());
}
+Result<void> IoPerfCollection::onWakeUpCollection(
+ time_t time, const wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const wp<ProcStatCollectorInterface>& procStatCollector) {
+ const sp<UidStatsCollectorInterface> uidStatsCollectorSp = uidStatsCollector.promote();
+ const sp<ProcStatCollectorInterface> procStatCollectorSp = procStatCollector.promote();
+ auto result = checkDataCollectors(uidStatsCollectorSp, procStatCollectorSp);
+ if (!result.ok()) {
+ return result;
+ }
+ Mutex::Autolock lock(mMutex);
+ return processLocked(time, std::unordered_set<std::string>(), uidStatsCollectorSp,
+ procStatCollectorSp, &mWakeUpCollection);
+}
+
Result<void> IoPerfCollection::onCustomCollection(
time_t time, [[maybe_unused]] SystemState systemState,
const std::unordered_set<std::string>& filterPackages,
diff --git a/cpp/watchdog/server/src/IoPerfCollection.h b/cpp/watchdog/server/src/IoPerfCollection.h
index 498413a..2ea8de4 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.h
+++ b/cpp/watchdog/server/src/IoPerfCollection.h
@@ -142,6 +142,7 @@
mBoottimeCollection({}),
mPeriodicCollection({}),
mUserSwitchCollections({}),
+ mWakeUpCollection({}),
mCustomCollection({}),
mLastMajorFaults(0) {}
@@ -150,10 +151,16 @@
std::string name() const override { return "IoPerfCollection"; }
// Implements DataProcessorInterface.
+ android::base::Result<void> onSystemStartup() override;
+
android::base::Result<void> onBoottimeCollection(
time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
+ android::base::Result<void> onWakeUpCollection(
+ time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const android::wp<ProcStatCollectorInterface>& procStatCollector) override;
+
android::base::Result<void> onPeriodicCollection(
time_t time, SystemState systemState,
const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
@@ -221,7 +228,8 @@
// Makes sure only one collection is running at any given time.
mutable Mutex mMutex;
- // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot.
+ // Info for the boot-time collection event. The cache is persisted until system shutdown/reboot
+ // or a wake-up collection occurs.
CollectionInfo mBoottimeCollection GUARDED_BY(mMutex);
// Info for the periodic collection event. The cache size is limited by
@@ -231,6 +239,9 @@
// Cache for user switch collection events. Events are cached from oldest to newest.
std::vector<UserSwitchCollectionInfo> mUserSwitchCollections GUARDED_BY(mMutex);
+ // Info for the wake-up collection event. Only the latest wake-up collection is cached.
+ CollectionInfo mWakeUpCollection GUARDED_BY(mMutex);
+
// Info for the custom collection event. The info is cleared at the end of every custom
// collection.
CollectionInfo mCustomCollection GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 9427322..3c3f2cb 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -170,10 +170,6 @@
switch (type) {
case aawi::StateType::POWER_CYCLE: {
PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
- if (powerCycle >= PowerCycle::NUM_POWER_CYLES) {
- return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Invalid power cycle %d", powerCycle));
- }
return handlePowerCycleChange(powerCycle);
}
case aawi::StateType::GARAGE_MODE: {
@@ -212,6 +208,11 @@
case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
ALOGI("Received SHUTDOWN_ENTER power cycle");
mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
+ mWatchdogPerfService->onShutdownEnter();
+ break;
+ case PowerCycle::POWER_CYCLE_SUSPEND_EXIT:
+ ALOGI("Received SUSPEND_EXIT power cycle");
+ mWatchdogPerfService->onSuspendExit();
break;
case PowerCycle::POWER_CYCLE_RESUME:
ALOGI("Received RESUME power cycle");
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.cpp b/cpp/watchdog/server/src/WatchdogPerfService.cpp
index a45dab2..40ed86a 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.cpp
+++ b/cpp/watchdog/server/src/WatchdogPerfService.cpp
@@ -75,7 +75,7 @@
"behavior is to list the results for the top N packages.\n"
"%s: Stops custom performance data collection and generates a dump of "
"the collection report.\n\n"
- "When no options are specified, the carwatchdog report contains the performance data "
+ "When no options are specified, the car watchdog report contains the performance data "
"collected during boot-time and over the last few minutes before the report generation.\n";
Result<std::chrono::seconds> parseSecondsFlag(const Vector<String16>& args, size_t pos) {
@@ -104,6 +104,8 @@
return "PERIODIC_COLLECTION";
case EventType::USER_SWITCH_COLLECTION:
return "USER_SWITCH_COLLECTION";
+ case EventType::WAKE_UP_COLLECTION:
+ return "WAKE_UP_COLLECTION";
case EventType::CUSTOM_COLLECTION:
return "CUSTOM_COLLECTION";
case EventType::PERIODIC_MONITOR:
@@ -112,6 +114,10 @@
return "LAST_EVENT";
case SwitchMessage::END_BOOTTIME_COLLECTION:
return "END_BOOTTIME_COLLECTION";
+ case SwitchMessage::END_USER_SWITCH_COLLECTION:
+ return "END_USER_SWITCH_COLLECTION";
+ case SwitchMessage::END_WAKE_UP_COLLECTION:
+ return "END_WAKE_UP_COLLECTION";
case SwitchMessage::END_CUSTOM_COLLECTION:
return "END_CUSTOM_COLLECTION";
default:
@@ -195,6 +201,11 @@
.interval = systemEventCollectionInterval,
.lastUptime = 0,
}};
+ mWakeUpCollection = {
+ .eventType = EventType::WAKE_UP_COLLECTION,
+ .interval = systemEventCollectionInterval,
+ .lastUptime = 0,
+ };
mPeriodicMonitor = {
.eventType = EventType::PERIODIC_MONITOR,
.interval = periodicMonitorInterval,
@@ -219,6 +230,7 @@
toString(mCurrCollectionEvent), toString(expected));
return;
}
+ notifySystemStartUpLocked();
mCurrCollectionEvent = EventType::BOOT_TIME_COLLECTION;
mBoottimeCollection.lastUptime = mHandlerLooper->now();
mHandlerLooper->setLooper(Looper::prepare(/*opts=*/0));
@@ -253,7 +265,7 @@
ALOGE("%s was terminated already", kServiceName);
return;
}
- ALOGE("Terminating %s as carwatchdog is terminating", kServiceName);
+ ALOGE("Terminating %s as car watchdog is terminating", kServiceName);
if (mCurrCollectionEvent != EventType::INIT) {
/*
* Looper runs only after EventType::INIT has completed so remove looper messages
@@ -309,7 +321,10 @@
Result<void> WatchdogPerfService::onUserStateChange(userid_t userId, const UserState& userState) {
Mutex::Autolock lock(mMutex);
- if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION) {
+ if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION ||
+ mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+ // Ignoring the user switch events because the boot-time and custom collections take
+ // precedence over other collections.
return {};
}
switch (static_cast<int>(userState)) {
@@ -389,6 +404,44 @@
return {};
}
+Result<void> WatchdogPerfService::onSuspendExit() {
+ Mutex::Autolock lock(mMutex);
+ if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+ // Ignoring the suspend exit event because the custom collection takes
+ // precedence over other collections.
+ ALOGE("Unable to start %s. Current performance data collection event: %s",
+ toString(EventType::WAKE_UP_COLLECTION), toString(mCurrCollectionEvent));
+ return {};
+ }
+ if (mCurrCollectionEvent == EventType::WAKE_UP_COLLECTION) {
+ ALOGE("The current performance data collection event is already %s",
+ toString(EventType::WAKE_UP_COLLECTION));
+ return {};
+ }
+ notifySystemStartUpLocked();
+ auto thiz = sp<WatchdogPerfService>::fromExisting(this);
+ mHandlerLooper->removeMessages(thiz);
+ mWakeUpCollection.lastUptime = mHandlerLooper->now();
+ nsecs_t uptime = mHandlerLooper->now() + mWakeUpDurationNs.count();
+ mHandlerLooper->sendMessageAtTime(uptime, thiz, SwitchMessage::END_WAKE_UP_COLLECTION);
+ mCurrCollectionEvent = EventType::WAKE_UP_COLLECTION;
+ mHandlerLooper->sendMessage(thiz, EventType::WAKE_UP_COLLECTION);
+ ALOGI("Switching to %s", toString(mCurrCollectionEvent));
+ return {};
+}
+
+Result<void> WatchdogPerfService::onShutdownEnter() {
+ Mutex::Autolock lock(mMutex);
+ if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
+ ALOGI("Unable to switch to %s during shutdown enter. Current performance data collection "
+ "event: %s",
+ toString(EventType::PERIODIC_COLLECTION), toString(mCurrCollectionEvent));
+ return {};
+ }
+ switchToPeriodicLocked(/*startNow=*/true);
+ return {};
+}
+
Result<void> WatchdogPerfService::onCustomCollection(int fd, const Vector<String16>& args) {
if (args.empty()) {
return Error(BAD_VALUE) << "No custom collection dump arguments";
@@ -483,6 +536,10 @@
kDumpMajorDelimiter.c_str(), std::string(33, '=').c_str()),
fd) ||
!WriteStringToFd(mBoottimeCollection.toString(), fd) ||
+ !WriteStringToFd(StringPrintf("\nWake-up collection information:\n%s\n",
+ std::string(31, '=').c_str()),
+ fd) ||
+ !WriteStringToFd(mWakeUpCollection.toString(), fd) ||
!WriteStringToFd(StringPrintf("\nUser-switch collection information:\n%s\n",
std::string(35, '=').c_str()),
fd) ||
@@ -603,28 +660,33 @@
return {};
}
+void WatchdogPerfService::switchToPeriodicLocked(bool startNow) {
+ if (mCurrCollectionEvent == EventType::PERIODIC_COLLECTION) {
+ ALOGW("The current performance data collection event is already %s",
+ toString(mCurrCollectionEvent));
+ return;
+ }
+ auto thiz = sp<WatchdogPerfService>::fromExisting(this);
+ mHandlerLooper->removeMessages(thiz);
+ mCurrCollectionEvent = EventType::PERIODIC_COLLECTION;
+ mPeriodicCollection.lastUptime = mHandlerLooper->now();
+ if (startNow) {
+ mHandlerLooper->sendMessage(thiz, EventType::PERIODIC_COLLECTION);
+ } else {
+ mPeriodicCollection.lastUptime += mPeriodicCollection.interval.count();
+ mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastUptime, thiz,
+ EventType::PERIODIC_COLLECTION);
+ }
+ mPeriodicMonitor.lastUptime = mHandlerLooper->now() + mPeriodicMonitor.interval.count();
+ mHandlerLooper->sendMessageAtTime(mPeriodicMonitor.lastUptime, thiz,
+ EventType::PERIODIC_MONITOR);
+ ALOGI("Switching to %s and %s", toString(mCurrCollectionEvent),
+ toString(EventType::PERIODIC_MONITOR));
+}
+
void WatchdogPerfService::handleMessage(const Message& message) {
Result<void> result;
- auto switchToPeriodicLocked = [&](bool startNow) {
- auto thiz = sp<WatchdogPerfService>::fromExisting(this);
- mHandlerLooper->removeMessages(thiz);
- mCurrCollectionEvent = EventType::PERIODIC_COLLECTION;
- mPeriodicCollection.lastUptime = mHandlerLooper->now();
- if (startNow) {
- mHandlerLooper->sendMessage(thiz, EventType::PERIODIC_COLLECTION);
- } else {
- mPeriodicCollection.lastUptime += mPeriodicCollection.interval.count();
- mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastUptime, thiz,
- EventType::PERIODIC_COLLECTION);
- }
- mPeriodicMonitor.lastUptime = mHandlerLooper->now() + mPeriodicMonitor.interval.count();
- mHandlerLooper->sendMessageAtTime(mPeriodicMonitor.lastUptime, thiz,
- EventType::PERIODIC_MONITOR);
- ALOGI("Switching to %s and %s", toString(mCurrCollectionEvent),
- toString(EventType::PERIODIC_MONITOR));
- };
-
switch (message.what) {
case static_cast<int>(EventType::BOOT_TIME_COLLECTION):
result = processCollectionEvent(&mBoottimeCollection);
@@ -642,13 +704,22 @@
case static_cast<int>(EventType::USER_SWITCH_COLLECTION):
result = processCollectionEvent(&mUserSwitchCollection);
break;
+ case static_cast<int>(EventType::WAKE_UP_COLLECTION):
+ result = processCollectionEvent(&mWakeUpCollection);
+ break;
case static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION):
+ case static_cast<int>(SwitchMessage::END_WAKE_UP_COLLECTION): {
mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
- if (result = processCollectionEvent(&mUserSwitchCollection); result.ok()) {
+ EventMetadata* eventMetadata =
+ message.what == static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION)
+ ? &mUserSwitchCollection
+ : &mWakeUpCollection;
+ if (result = processCollectionEvent(eventMetadata); result.ok()) {
Mutex::Autolock lock(mMutex);
switchToPeriodicLocked(/*startNow=*/false);
}
break;
+ }
case static_cast<int>(EventType::CUSTOM_COLLECTION):
result = processCollectionEvent(&mCustomCollection);
break;
@@ -764,6 +835,9 @@
mUidStatsCollector, mProcStatCollector);
break;
}
+ case EventType::WAKE_UP_COLLECTION:
+ result = processor->onWakeUpCollection(now, mUidStatsCollector, mProcStatCollector);
+ break;
case EventType::CUSTOM_COLLECTION:
result = processor->onCustomCollection(now, mSystemState, metadata->filterPackages,
mUidStatsCollector, mProcStatCollector);
@@ -846,6 +920,16 @@
return {};
}
+Result<void> WatchdogPerfService::notifySystemStartUpLocked() {
+ for (const auto& processor : mDataProcessors) {
+ if (const auto result = processor->onSystemStartup(); !result.ok()) {
+ ALOGE("%s failed to process system startup event", processor->name().c_str());
+ return Error() << processor->name() << " failed to process system startup event";
+ }
+ }
+ return {};
+}
+
WatchdogPerfService::EventMetadata* WatchdogPerfService::currCollectionMetadataLocked() {
switch (mCurrCollectionEvent) {
case EventType::BOOT_TIME_COLLECTION:
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.h b/cpp/watchdog/server/src/WatchdogPerfService.h
index 3f412f8..9302611 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.h
+++ b/cpp/watchdog/server/src/WatchdogPerfService.h
@@ -55,6 +55,7 @@
} // namespace internal
constexpr std::chrono::seconds kDefaultPostSystemEventDurationSec = 30s;
+constexpr std::chrono::seconds kDefaultWakeUpEventDurationSec = 30s;
constexpr std::chrono::seconds kDefaultUserSwitchTimeoutSec = 30s;
constexpr const char* kStartCustomCollectionFlag = "--start_perf";
constexpr const char* kEndCustomCollectionFlag = "--stop_perf";
@@ -81,10 +82,17 @@
virtual android::base::Result<void> init() = 0;
// Callback to terminate the data processor.
virtual void terminate() = 0;
+ // Callback to perform actions (such as clearing stats from previous system startup events)
+ // before starting boot-time or wake-up collections.
+ virtual android::base::Result<void> onSystemStartup() = 0;
// Callback to process the data collected during boot-time.
virtual android::base::Result<void> onBoottimeCollection(
time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
+ // Callback to process the data collected during a wake-up event.
+ virtual android::base::Result<void> onWakeUpCollection(
+ time_t time, const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
+ const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
// Callback to process the data collected periodically post boot complete.
virtual android::base::Result<void> onPeriodicCollection(
time_t time, SystemState systemState,
@@ -95,6 +103,7 @@
time_t time, userid_t from, userid_t to,
const android::wp<UidStatsCollectorInterface>& uidStatsCollector,
const android::wp<ProcStatCollectorInterface>& procStatCollector) = 0;
+
/**
* Callback to process the data collected on custom collection and filter the results only to
* the specified |filterPackages|.
@@ -128,6 +137,7 @@
BOOT_TIME_COLLECTION,
PERIODIC_COLLECTION,
USER_SWITCH_COLLECTION,
+ WAKE_UP_COLLECTION,
CUSTOM_COLLECTION,
// Monitor event.
@@ -150,6 +160,12 @@
END_USER_SWITCH_COLLECTION,
/**
+ * On receiving this message, collect the last wake up record and start periodic collection and
+ * monitor.
+ */
+ END_WAKE_UP_COLLECTION,
+
+ /**
* On receiving this message, ends custom collection, discard collected data and start periodic
* collection and monitor.
*/
@@ -157,9 +173,9 @@
};
/**
- * WatchdogPerfServiceInterface collects performance data during boot-time and periodically post
- * boot complete. It exposes APIs that the main thread and binder service can call to start a
- * collection, switch the collection type, and generate collection dumps.
+ * WatchdogPerfServiceInterface collects performance data during boot-time, user switch, system wake
+ * up and periodically post system events. It exposes APIs that the main thread and binder service
+ * can call to start a collection, switch the collection type, and generate collection dumps.
*/
class WatchdogPerfServiceInterface : public MessageHandler {
public:
@@ -182,6 +198,10 @@
virtual android::base::Result<void> onUserStateChange(
userid_t userId,
const android::automotive::watchdog::internal::UserState& userState) = 0;
+ // Starts wake-up collection. Any running collection is stopped, except for custom collections.
+ virtual android::base::Result<void> onSuspendExit() = 0;
+ // Called on shutdown enter, suspend enter and hibernation enter.
+ virtual android::base::Result<void> onShutdownEnter() = 0;
/**
* Depending on the arguments, it either:
@@ -203,6 +223,9 @@
mPostSystemEventDurationNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::seconds(sysprop::postSystemEventDuration().value_or(
kDefaultPostSystemEventDurationSec.count())))),
+ mWakeUpDurationNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::seconds(sysprop::wakeUpEventDuration().value_or(
+ kDefaultWakeUpEventDurationSec.count())))),
mUserSwitchTimeoutNs(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::seconds(sysprop::userSwitchTimeout().value_or(
kDefaultUserSwitchTimeoutSec.count())))),
@@ -234,6 +257,10 @@
userid_t userId,
const android::automotive::watchdog::internal::UserState& userState) override;
+ android::base::Result<void> onSuspendExit() override;
+
+ android::base::Result<void> onShutdownEnter() override;
+
android::base::Result<void> onCustomCollection(int fd,
const Vector<android::String16>& args) override;
@@ -290,6 +317,9 @@
// Start a user switch collection.
android::base::Result<void> startUserSwitchCollection();
+ // Switch to periodic collection and periodic monitor.
+ void switchToPeriodicLocked(bool startNow);
+
// Handles the messages received by the lopper.
void handleMessage(const Message& message) override;
@@ -302,6 +332,11 @@
// Processes the monitor events received by |handleMessage|.
android::base::Result<void> processMonitorEvent(EventMetadata* metadata);
+ // Notifies all registered data processors that either boot-time or wake-up collection will
+ // start. Individual implementations of data processors may clear stats collected during
+ // previous system startup events.
+ android::base::Result<void> notifySystemStartUpLocked();
+
/**
* Returns the metadata for the current collection based on |mCurrCollectionEvent|. Returns
* nullptr on invalid collection event.
@@ -311,6 +346,9 @@
// Duration to extend a system event collection after the final signal is received.
std::chrono::nanoseconds mPostSystemEventDurationNs;
+ // Duration of the wake-up collection event.
+ std::chrono::nanoseconds mWakeUpDurationNs;
+
// Timeout duration for user switch collection in case final signal isn't received.
std::chrono::nanoseconds mUserSwitchTimeoutNs;
@@ -335,6 +373,9 @@
// Info for the |EventType::USER_SWITCH_COLLECTION| collection event.
UserSwitchEventMetadata mUserSwitchCollection GUARDED_BY(mMutex);
+ // Info for the |EventType::WAKE_UP_COLLECTION| collection event.
+ EventMetadata mWakeUpCollection GUARDED_BY(mMutex);
+
// Info for the |EventType::CUSTOM_COLLECTION| collection event. The info is cleared at the end
// of every custom collection.
EventMetadata mCustomCollection GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 9c785b4..28e77a9 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -34,6 +34,7 @@
#include <android/automotive/watchdog/internal/BnCarWatchdogServiceForSystem.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/SystemClock.h>
@@ -90,6 +91,7 @@
// TimeoutLength::TIMEOUT_NORMAL.
const int32_t MSG_VHAL_WATCHDOG_ALIVE = static_cast<int>(TimeoutLength::TIMEOUT_NORMAL) + 1;
const int32_t MSG_VHAL_HEALTH_CHECK = MSG_VHAL_WATCHDOG_ALIVE + 1;
+const int32_t MSG_CACHE_VHAL_PROCESS_IDENTIFIER = MSG_VHAL_HEALTH_CHECK + 1;
// VHAL is supposed to send heart beat every 3s. Car watchdog checks if there is the latest heart
// beat from VHAL within 3s, allowing 1s marginal time.
@@ -103,7 +105,9 @@
constexpr const char kPropertyVhalCheckInterval[] = "ro.carwatchdog.vhal_healthcheck.interval";
constexpr const char kPropertyClientCheckInterval[] = "ro.carwatchdog.client_healthcheck.interval";
constexpr const char kServiceName[] = "WatchdogProcessService";
-constexpr const char kVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
+constexpr const char kHidlVhalInterfaceName[] = "android.hardware.automotive.vehicle@2.0::IVehicle";
+constexpr const char kAidlVhalInterfaceName[] =
+ "android.hardware.automotive.vehicle.IVehicle/default";
std::string toPidString(const std::vector<ProcessIdentifier>& processIdentifiers) {
size_t size = processIdentifiers.size();
@@ -133,6 +137,42 @@
return pidStat->startTimeMillis;
}
+Result<pid_t> queryHidlServiceManagerForVhalPid() {
+ using android::hidl::manager::V1_0::IServiceManager;
+ pid_t pid = -1;
+ Return<void> ret = IServiceManager::getService()->debugDump([&](auto& hals) {
+ for (const auto& info : hals) {
+ if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
+ continue;
+ }
+ if (info.interfaceName == kHidlVhalInterfaceName) {
+ pid = info.pid;
+ return;
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ return Error() << "Failed to get VHAL process id from HIDL service manager";
+ }
+ if (pid == -1) {
+ return Error() << "No VHAL service registered to HIDL service manager";
+ }
+ return pid;
+}
+
+Result<pid_t> queryAidlServiceManagerForVhalPid() {
+ using ServiceDebugInfo = android::IServiceManager::ServiceDebugInfo;
+ std::vector<ServiceDebugInfo> serviceDebugInfos =
+ defaultServiceManager()->getServiceDebugInfo();
+ for (const auto& serviceDebugInfo : serviceDebugInfos) {
+ if (serviceDebugInfo.name == kAidlVhalInterfaceName) {
+ return serviceDebugInfo.pid;
+ }
+ }
+ return Error() << "No VHAL service registered to AIDL service manager";
+}
+
} // namespace
WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
@@ -312,7 +352,7 @@
status = tellClientAliveLocked(BnCarWatchdogServiceForSystem::asBinder(service), sessionId);
}
if (status.isOk()) {
- dumpAndKillAllProcesses(clientsNotResponding, true);
+ dumpAndKillAllProcesses(clientsNotResponding, /*reportToVhal=*/true);
}
return status;
}
@@ -403,6 +443,13 @@
WriteStringToFd(StringPrintf("%sVHAL health check interval: %lldms\n", indent,
mVhalHealthCheckWindowMs.count()),
fd);
+ if (mVhalProcessIdentifier.has_value()) {
+ WriteStringToFd(StringPrintf("%sVHAL process identifier (PID = %d, Start time millis = "
+ "%" PRIi64 ")",
+ indent, mVhalProcessIdentifier->pid,
+ mVhalProcessIdentifier->startTimeMillis),
+ fd);
+ }
return {};
}
@@ -658,7 +705,7 @@
for (const ClientInfo*& clientInfo : clientsToNotify) {
clientInfo->prepareProcessTermination();
}
- return dumpAndKillAllProcesses(processIdentifiers, true);
+ return dumpAndKillAllProcesses(processIdentifiers, /*reportToVhal=*/true);
}
Result<void> WatchdogProcessService::dumpAndKillAllProcesses(
@@ -868,6 +915,36 @@
std::chrono::nanoseconds intervalNs = mVhalHealthCheckWindowMs + kHealthCheckDelayMs;
mHandlerLooper->sendMessageDelayed(intervalNs.count(), mMessageHandler,
Message(MSG_VHAL_HEALTH_CHECK));
+ // VHAL process identifier is required only when termiating the VHAL process. VHAL process is
+ // terminated only when the VHAL is unhealthy. However, caching the process identifier as soon
+ // as connecting to VHAL guarantees the correct PID is cached. Because the VHAL pid is queried
+ // from the service manager, the caching should be performed outside the class level lock. So,
+ // handle the caching in the handler thread after successfully subscribing to the VHAL_HEARTBEAT
+ // property.
+ mHandlerLooper->sendMessage(mMessageHandler, Message(MSG_CACHE_VHAL_PROCESS_IDENTIFIER));
+ return;
+}
+
+bool WatchdogProcessService::cacheVhalProcessIdentifier() {
+ pid_t pid = -1;
+ if (Result<pid_t> hidlResult = queryHidlServiceManagerForVhalPid(); hidlResult.ok()) {
+ pid = *hidlResult;
+ ALOGI("Fetched HIDL VHAL PID %d", pid);
+ } else if (Result<pid_t> aidlResult = queryAidlServiceManagerForVhalPid(); aidlResult.ok()) {
+ pid = *aidlResult;
+ ALOGI("Fetched AIDL VHAL PID %d", pid);
+ } else {
+ ALOGE("Failed to fetch VHAL pid:\n\t%s\n\t%s", hidlResult.error().message().c_str(),
+ aidlResult.error().message().c_str());
+ return false;
+ }
+ ProcessIdentifier processIdentifier;
+ processIdentifier.pid = pid;
+ processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(pid);
+
+ Mutex::Autolock lock(mMutex);
+ mVhalProcessIdentifier = processIdentifier;
+ return true;
}
int32_t WatchdogProcessService::getNewSessionId() {
@@ -916,34 +993,25 @@
}
void WatchdogProcessService::terminateVhal() {
- using android::hidl::manager::V1_0::IServiceManager;
-
- std::vector<ProcessIdentifier> processIdentifiers;
- sp<IServiceManager> manager = IServiceManager::getService();
- Return<void> ret = manager->debugDump([&](auto& hals) {
- for (const auto& info : hals) {
- if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
- continue;
- }
- // TODO(b/216735836): terminate AIDL VHAL.
- if (info.interfaceName == kVhalInterfaceName) {
- ProcessIdentifier processIdentifier;
- processIdentifier.pid = info.pid;
- processIdentifier.startTimeMillis = mGetStartTimeForPidFunc(info.pid);
- processIdentifiers.push_back(processIdentifier);
- break;
- }
+ auto maybeDumpAndKillVhalProcess = [&]() -> bool {
+ std::optional<ProcessIdentifier> processIdentifier;
+ {
+ Mutex::Autolock lock(mMutex);
+ processIdentifier = mVhalProcessIdentifier;
}
- });
-
- if (!ret.isOk()) {
- ALOGE("Failed to terminate VHAL: could not get VHAL process id");
- return;
- } else if (processIdentifiers.empty()) {
- ALOGE("Failed to terminate VHAL: VHAL is not running");
+ if (!processIdentifier.has_value()) {
+ return false;
+ }
+ dumpAndKillAllProcesses(std::vector<ProcessIdentifier>(1, *processIdentifier),
+ /*reportToVhal=*/false);
+ return true;
+ };
+ if (maybeDumpAndKillVhalProcess()) {
return;
}
- dumpAndKillAllProcesses(processIdentifiers, false);
+ if (!cacheVhalProcessIdentifier() || !maybeDumpAndKillVhalProcess()) {
+ ALOGE("Failed to termitate VHAL: failed to fetch VHAL PID");
+ }
}
std::chrono::nanoseconds WatchdogProcessService::getTimeoutDurationNs(
@@ -1066,6 +1134,9 @@
case MSG_VHAL_HEALTH_CHECK:
mService->checkVhalHealth();
break;
+ case MSG_CACHE_VHAL_PROCESS_IDENTIFIER:
+ mService->cacheVhalProcessIdentifier();
+ break;
default:
ALOGW("Unknown message: %d", message.what);
}
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h
index 1bb8efe..c0bf3bf 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.h
+++ b/cpp/watchdog/server/src/WatchdogProcessService.h
@@ -37,6 +37,7 @@
#include <IVhalClient.h>
#include <VehicleHalTypes.h>
+#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -249,6 +250,7 @@
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
android::base::Result<void> connectToVhalLocked();
void subscribeToVhalHeartBeatLocked();
+ bool cacheVhalProcessIdentifier();
void reportWatchdogAliveToVhal();
void reportTerminatedProcessToVhal(
const std::vector<android::automotive::watchdog::internal::ProcessIdentifier>&
@@ -296,6 +298,8 @@
bool mIsEnabled GUARDED_BY(mMutex);
std::shared_ptr<android::frameworks::automotive::vhal::IVhalClient> mVhalService
GUARDED_BY(mMutex);
+ std::optional<android::automotive::watchdog::internal::ProcessIdentifier> mVhalProcessIdentifier
+ GUARDED_BY(mMutex);
HeartBeat mVhalHeartBeat GUARDED_BY(mMutex);
android::sp<WatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mMutex);
android::sp<BinderDeathRecipient> mBinderDeathRecipient GUARDED_BY(mMutex);
diff --git a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
index 20f3b14..db67e79 100644
--- a/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
+++ b/cpp/watchdog/server/sysprop/WatchdogProperties.sysprop
@@ -42,6 +42,15 @@
prop_name: "ro.carwatchdog.post_system_event_duration"
}
+# Duration in seconds of data collection for a system wake up event.
+prop {
+ api_name: "wakeUpEventDuration"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.carwatchdog.wake_up_event_duration"
+}
+
# Maximum number of periodically collected records to be cached in memory.
prop {
api_name: "periodicCollectionBufferSize"
diff --git a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
index da8cfe1..e93849c 100644
--- a/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
+++ b/cpp/watchdog/server/sysprop/api/libwatchdog_properties-latest.txt
@@ -19,6 +19,12 @@
prop_name: "ro.carwatchdog.post_system_event_duration"
}
prop {
+ api_name: "wakeUpEventDuration"
+ type: Integer
+ scope: Internal
+ prop_name: "ro.carwatchdog.wake_up_event_duration"
+ }
+ prop {
api_name: "periodicCollectionBufferSize"
type: Integer
scope: Internal
diff --git a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
index 2bbd11f..f7b4f24 100644
--- a/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
+++ b/cpp/watchdog/server/tests/IoPerfCollectionTest.cpp
@@ -458,6 +458,11 @@
return mCollector->mUserSwitchCollections;
}
+ const CollectionInfo& getWakeUpCollectionInfo() {
+ Mutex::Autolock lock(mCollector->mMutex);
+ return mCollector->mWakeUpCollection;
+ }
+
const CollectionInfo& getCustomCollectionInfo() {
Mutex::Autolock lock(mCollector->mMutex);
return mCollector->mCustomCollection;
@@ -548,8 +553,69 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
- << "Periodic and user-switch collections shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Periodic, wake-up and user-switch collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestOnWakeUpCollection) {
+ const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+ const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(uidStats));
+ EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(procStatInfo));
+
+ time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ ASSERT_RESULT_OK(
+ mCollector->onWakeUpCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+ const auto actual = mCollectorPeer->getWakeUpCollectionInfo();
+
+ const CollectionInfo expected{
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .records = {{
+ .systemSummaryStats = systemSummaryStats,
+ .userPackageSummaryStats = userPackageSummaryStats,
+ }},
+ };
+
+ EXPECT_THAT(actual, CollectionInfoEq(expected))
+ << "Wake-up collection info doesn't match.\nExpected:\n"
+ << expected.toString() << "\nActual:\n"
+ << actual.toString();
+
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Boot-time, periodic, and user-switch collections shouldn't be reported";
+}
+
+TEST_F(IoPerfCollectionTest, TestOnSystemStartup) {
+ const auto [uidStats, userPackageSummaryStats] = sampleUidStats();
+ const auto [procStatInfo, systemSummaryStats] = sampleProcStat();
+
+ EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(uidStats));
+ EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillRepeatedly(Return(procStatInfo));
+
+ time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ ASSERT_RESULT_OK(
+ mCollector->onBoottimeCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+ ASSERT_RESULT_OK(
+ mCollector->onWakeUpCollection(now, mMockUidStatsCollector, mMockProcStatCollector));
+
+ auto actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
+ auto actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
+
+ EXPECT_THAT(actualBoottimeCollection.records.size(), 1)
+ << "Boot-time collection records is empty.";
+ EXPECT_THAT(actualWakeUpCollection.records.size(), 1) << "Wake-up collection records is empty.";
+
+ ASSERT_RESULT_OK(mCollector->onSystemStartup());
+
+ actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
+ actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
+
+ EXPECT_THAT(actualBoottimeCollection.records.size(), 0)
+ << "Boot-time collection records is not empty.";
+ EXPECT_THAT(actualWakeUpCollection.records.size(), 0)
+ << "Wake-up collection records is not empty.";
}
TEST_F(IoPerfCollectionTest, TestOnUserSwitchCollection) {
@@ -652,8 +718,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
- << "Boottime and Periodic collections shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Boot-time, wake-up and periodic collections shouldn't be reported";
}
TEST_F(IoPerfCollectionTest, TestUserSwitchCollectionsMaxCacheSize) {
@@ -750,8 +816,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
- << "Boot-time and user-switch collections shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Boot-time, wake-up and user-switch collections shouldn't be reported";
}
TEST_F(IoPerfCollectionTest, TestOnCustomCollectionWithoutPackageFilter) {
@@ -914,8 +980,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
- << "Boot-time and user-switch collections shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Boot-time, wake-up and user-switch collections shouldn't be reported";
}
TEST_F(IoPerfCollectionTest, TestConsecutiveOnPeriodicCollection) {
@@ -962,8 +1028,8 @@
<< expected.toString() << "\nActual:\n"
<< actual.toString();
- ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/2))
- << "Boot-time and user-switch collection shouldn't be reported";
+ ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
+ << "Boot-time, wake-up and user-switch collection shouldn't be reported";
}
} // namespace watchdog
diff --git a/cpp/watchdog/server/tests/MockDataProcessor.h b/cpp/watchdog/server/tests/MockDataProcessor.h
index 8abc753..01224db 100644
--- a/cpp/watchdog/server/tests/MockDataProcessor.h
+++ b/cpp/watchdog/server/tests/MockDataProcessor.h
@@ -33,10 +33,15 @@
MOCK_METHOD(std::string, name, (), (const, override));
MOCK_METHOD(android::base::Result<void>, init, (), (override));
MOCK_METHOD(void, terminate, (), (override));
+ MOCK_METHOD(android::base::Result<void>, onSystemStartup, (), (override));
MOCK_METHOD(android::base::Result<void>, onBoottimeCollection,
(time_t, const wp<UidStatsCollectorInterface>&,
const wp<ProcStatCollectorInterface>&),
(override));
+ MOCK_METHOD(android::base::Result<void>, onWakeUpCollection,
+ (time_t, const wp<UidStatsCollectorInterface>&,
+ const wp<ProcStatCollectorInterface>&),
+ (override));
MOCK_METHOD(android::base::Result<void>, onPeriodicCollection,
(time_t, SystemState, const wp<UidStatsCollectorInterface>&,
const wp<ProcStatCollectorInterface>&),
diff --git a/cpp/watchdog/server/tests/MockWatchdogPerfService.h b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
index 9aebb2f..13f78d5 100644
--- a/cpp/watchdog/server/tests/MockWatchdogPerfService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
@@ -43,6 +43,8 @@
(userid_t userId,
const android::automotive::watchdog::internal::UserState& userState),
(override));
+ MOCK_METHOD(android::base::Result<void>, onSuspendExit, (), (override));
+ MOCK_METHOD(android::base::Result<void>, onShutdownEnter, (), (override));
MOCK_METHOD(android::base::Result<void>, onCustomCollection,
(int fd, const Vector<android::String16>& args), (override));
MOCK_METHOD(android::base::Result<void>, onDump, (int fd), (const, override));
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index cf72613..3329691 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -378,6 +378,8 @@
TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToShutdownEnter) {
setSystemCallingUid();
EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(/*isEnabled=*/false)).Times(1);
+ EXPECT_CALL(*mMockWatchdogPerfService, onShutdownEnter()).Times(1);
+
Status status =
mWatchdogInternalHandler
->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
@@ -398,6 +400,20 @@
ASSERT_TRUE(status.isOk()) << status;
}
+TEST_F(WatchdogInternalHandlerTest, TestNotifyPowerCycleChangeToSuspendExit) {
+ setSystemCallingUid();
+
+ EXPECT_CALL(*mMockWatchdogPerfService, onSuspendExit()).Times(1);
+
+ auto status = mWatchdogInternalHandler
+ ->notifySystemStateChange(aawi::StateType::POWER_CYCLE,
+ static_cast<int32_t>(
+ PowerCycle::POWER_CYCLE_SUSPEND_EXIT),
+ -1);
+
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
TEST_F(WatchdogInternalHandlerTest, TestErrorOnNotifyPowerCycleChangeWithInvalidArgs) {
EXPECT_CALL(*mMockWatchdogProcessService, setEnabled(_)).Times(0);
EXPECT_CALL(*mMockWatchdogPerfService, setSystemState(_)).Times(0);
diff --git a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
index 679e57e..46594de 100644
--- a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
@@ -62,6 +62,7 @@
constexpr std::chrono::seconds kTestCustomCollectionDuration = 11s;
constexpr std::chrono::seconds kTestPeriodicMonitorInterval = 2s;
constexpr std::chrono::seconds kTestUserSwitchTimeout = 15s;
+constexpr std::chrono::seconds kTestWakeUpDuration = 20s;
namespace internal {
@@ -89,6 +90,7 @@
mService->mUserSwitchCollection.interval = kTestSystemEventCollectionInterval;
mService->mPeriodicMonitor.interval = kTestPeriodicMonitorInterval;
mService->mUserSwitchTimeoutNs = kTestUserSwitchTimeout;
+ mService->mWakeUpDurationNs = kTestWakeUpDuration;
}
void clearPostSystemEventDuration() {
@@ -149,6 +151,7 @@
mMockProcDiskStatsCollector);
EXPECT_CALL(*mMockDataProcessor, init()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
ASSERT_RESULT_OK(mService->registerDataProcessor(mMockDataProcessor));
@@ -222,6 +225,7 @@
mMockProcDiskStatsCollector);
EXPECT_CALL(*mMockDataProcessor, init()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
ASSERT_RESULT_OK(mService->registerDataProcessor(mMockDataProcessor));
@@ -233,6 +237,19 @@
ASSERT_TRUE(mService->mCollectionThread.joinable()) << "Collection thread not created";
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "Boot-time collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+ << "Invalid collection event";
+
ASSERT_FALSE(mService->start().ok())
<< "No error returned when WatchdogPerfService was started more than once";
@@ -1059,6 +1076,108 @@
ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
}
+TEST_F(WatchdogPerfServiceTest, TestWakeUpCollection) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ // #1 Wake up collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor, onSystemStartup()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mService->onSuspendExit());
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Wake up collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::WAKE_UP_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // #2 Wake up collections before duration expires
+ int maxIterations = static_cast<int>(kTestWakeUpDuration.count() /
+ kTestSystemEventCollectionInterval.count());
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(maxIterations);
+ EXPECT_CALL(*mMockDataProcessor,
+ onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(maxIterations);
+
+ // Poll all remaining wake up collections except last
+ for (int i = 0; i < maxIterations - 1; ++i) {
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Subsequent wake up collection didn't happen at "
+ << kTestSystemEventCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::WAKE_UP_COLLECTION)
+ << "Invalid collection event";
+ }
+
+ // Suspend exit signal should be ignored since already running wake up collection.
+ ASSERT_RESULT_OK(mService->onSuspendExit());
+
+ // Poll the last wake up collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestSystemEventCollectionInterval.count())
+ << "Last wake up collection didn't happen immediately after sending "
+ << "END_WAKE_UP_COLLECTION message";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestWakeUpCollectionDuringCustomCollection) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ // Start custom collection
+ Vector<String16> args;
+ args.push_back(String16(kStartCustomCollectionFlag));
+ args.push_back(String16(kIntervalFlag));
+ args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
+ args.push_back(String16(kMaxDurationFlag));
+ args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+ ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(2);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(2);
+ EXPECT_CALL(*mMockDataProcessor,
+ onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(2);
+ EXPECT_CALL(*mMockDataProcessor,
+ onWakeUpCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(0);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+ << "Invalid collection event";
+
+ // Custom collection while suspend exit signal is received
+ ASSERT_RESULT_OK(mService->onSuspendExit());
+
+ // Continued custom collection
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestCustomCollectionInterval.count())
+ << "Subsequent custom collection didn't happen at "
+ << kTestCustomCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
TEST_F(WatchdogPerfServiceTest, TestPeriodicMonitorRequestsCollection) {
ASSERT_NO_FATAL_FAILURE(startService());
@@ -1096,6 +1215,93 @@
EXPECT_CALL(*mMockDataProcessor, terminate()).Times(1);
}
+TEST_F(WatchdogPerfServiceTest, TestShutdownEnter) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ // Start boot-time collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onBoottimeCollection(_, Eq(mMockUidStatsCollector), Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "Boot-time collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::BOOT_TIME_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ ASSERT_RESULT_OK(mService->onShutdownEnter());
+
+ // Switch to periodic collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onPeriodicCollection(_, SystemState::NORMAL_MODE, Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0)
+ << "Periodic collection didn't start immediately after receiving shutdown enter signal";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::PERIODIC_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
+TEST_F(WatchdogPerfServiceTest, TestShutdownEnterWithCustomCollection) {
+ ASSERT_NO_FATAL_FAILURE(startService());
+
+ ASSERT_NO_FATAL_FAILURE(startPeriodicCollection());
+
+ // Start custom collection
+ Vector<String16> args;
+ args.push_back(String16(kStartCustomCollectionFlag));
+ args.push_back(String16(kIntervalFlag));
+ args.push_back(String16(std::to_string(kTestCustomCollectionInterval.count()).c_str()));
+ args.push_back(String16(kMaxDurationFlag));
+ args.push_back(String16(std::to_string(kTestCustomCollectionDuration.count()).c_str()));
+
+ ASSERT_RESULT_OK(mService->onCustomCollection(-1, args));
+
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), 0) << "Custom collection didn't start immediately";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+
+ // Suspend in middle of custom collection
+ ASSERT_RESULT_OK(mService->onShutdownEnter());
+
+ // Custom collection
+ EXPECT_CALL(*mMockUidStatsCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockProcStatCollector, collect()).Times(1);
+ EXPECT_CALL(*mMockDataProcessor,
+ onCustomCollection(_, SystemState::NORMAL_MODE, _, Eq(mMockUidStatsCollector),
+ Eq(mMockProcStatCollector)))
+ .Times(1);
+
+ ASSERT_RESULT_OK(mLooperStub->pollCache());
+
+ ASSERT_EQ(mLooperStub->numSecondsElapsed(), kTestCustomCollectionInterval.count())
+ << "Subsequent custom collection didn't happen at "
+ << kTestCustomCollectionInterval.count() << " seconds interval";
+ ASSERT_EQ(mServicePeer->getCurrCollectionEvent(), EventType::CUSTOM_COLLECTION)
+ << "Invalid collection event";
+ ASSERT_NO_FATAL_FAILURE(verifyAndClearExpectations());
+}
+
TEST_F(WatchdogPerfServiceTest, TestSystemStateSwitch) {
ASSERT_NO_FATAL_FAILURE(startService());
diff --git a/data/etc/android.car.cluster.xml b/data/etc/android.car.cluster.xml
index 191ded5..3cc4aae 100644
--- a/data/etc/android.car.cluster.xml
+++ b/data/etc/android.car.cluster.xml
@@ -22,6 +22,7 @@
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.car.permission.CAR_ENGINE_DETAILED"/>
<permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
+ <permission name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
</privapp-permissions>
</permissions>
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index 8a98780..5850d3e 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -22,8 +22,9 @@
android:sharedUserId="android.uid.system">
<application android:label="@string/development_settings_title"
+ android:theme="@style/Theme.CDOBaseTheme"
tools:node="merge"
- tools:replace="android:label">
+ tools:replace="android:label,android:theme">
<activity
android:name=".CarDevelopmentSettingsDashboardActivity"
diff --git a/packages/CarDeveloperOptions/res/values/themes.xml b/packages/CarDeveloperOptions/res/values/themes.xml
index 43887b3..1eea0e7 100644
--- a/packages/CarDeveloperOptions/res/values/themes.xml
+++ b/packages/CarDeveloperOptions/res/values/themes.xml
@@ -39,6 +39,13 @@
<item name="buttonBarButtonStyle">@*android:style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item>
</style>
+ <!-- Base settings application theme with minor modifications for visibility -->
+ <style name="Theme.CDOBaseTheme" parent="@style/Theme.Settings">
+ <item name="android:textAppearanceListItem">@style/CDOTitleTextAppearance</item>
+ <item name="android:textColor">@*android:color/car_body1</item>
+ <item name="android:textColorSecondary">@*android:color/car_body1</item>
+ </style>
+
<style name="Theme.SubSettings" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="alertDialogTheme">@style/Theme.AlertDialog</item>
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
@@ -57,15 +64,20 @@
<style name="Theme.CarDeveloperOptions" parent="@style/Theme.CarUi.WithToolbar">
<item name="alertDialogTheme">@style/Theme.AlertDialog</item>
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
- <item name="preferenceTheme">@style/CarDeveloperOptionsPreferenceTheme</item>
+ <item name="preferenceTheme">@style/CDOPreferenceTheme</item>
</style>
- <style name="CarDeveloperOptionsPreferenceTheme" parent="@style/CarUiPreferenceTheme">
- <item name="preferenceFragmentCompatStyle">@style/CarDeveloperOptionsPreferenceFragment</item>
- <item name="preferenceFragmentStyle">@style/CarDeveloperOptionsPreferenceFragment</item>
+ <style name="CDOPreferenceTheme" parent="@style/CarUiPreferenceTheme">
+ <item name="preferenceFragmentCompatStyle">@style/CDOPreferenceFragment</item>
+ <item name="preferenceFragmentStyle">@style/CDOPreferenceFragment</item>
</style>
- <style name="CarDeveloperOptionsPreferenceFragment" parent="@style/PreferenceFragment.CarUi">
+ <style name="CDOPreferenceFragment" parent="@style/PreferenceFragment.CarUi">
<item name="android:layout">@layout/preference_list_fragment</item>
</style>
-</resources>
\ No newline at end of file
+
+ <style name="CDOTitleTextAppearance" parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">@*android:dimen/car_body2_size</item>
+ <item name="android:textColor">@*android:color/car_body1</item>
+ </style>
+</resources>
diff --git a/packages/ScriptExecutor/Android.bp b/packages/ScriptExecutor/Android.bp
index 7258589..c126c7f 100644
--- a/packages/ScriptExecutor/Android.bp
+++ b/packages/ScriptExecutor/Android.bp
@@ -78,6 +78,10 @@
enabled: false,
},
+ libs: [
+ "android.car",
+ ],
+
jni_libs: [
"libscriptexecutorjni",
],
@@ -99,5 +103,9 @@
"src/**/*.java",
],
+ libs: [
+ "android.car",
+ ],
+
sdk_version: "test_current",
}
diff --git a/packages/ScriptExecutor/src/BundleWrapper.cpp b/packages/ScriptExecutor/src/BundleWrapper.cpp
index 88403b0..799f37c 100644
--- a/packages/ScriptExecutor/src/BundleWrapper.cpp
+++ b/packages/ScriptExecutor/src/BundleWrapper.cpp
@@ -17,6 +17,7 @@
#include "BundleWrapper.h"
#include "JniUtils.h"
+#include "jni.h"
#include "nativehelper/scoped_local_ref.h"
namespace com {
@@ -106,6 +107,37 @@
return {}; // ok result
}
+Result<void> BundleWrapper::putBooleanArray(const char* key,
+ const std::vector<unsigned char>& value) {
+ ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+ if (keyStringRef == nullptr) {
+ return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+ }
+
+ jmethodID putBooleanArrayMethod =
+ mJNIEnv->GetMethodID(mBundleClass, "putBooleanArray", "(Ljava/lang/String;[Z)V");
+
+ ScopedLocalRef<jbooleanArray> arrayRef(mJNIEnv, mJNIEnv->NewBooleanArray(value.size()));
+ mJNIEnv->SetBooleanArrayRegion(arrayRef.get(), 0, value.size(), &value.at(0));
+ mJNIEnv->CallVoidMethod(mBundle, putBooleanArrayMethod, keyStringRef.get(), arrayRef.get());
+ return {}; // ok result
+}
+
+Result<void> BundleWrapper::putDoubleArray(const char* key, const std::vector<double>& value) {
+ ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+ if (keyStringRef == nullptr) {
+ return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+ }
+
+ jmethodID putDoubleArrayMethod =
+ mJNIEnv->GetMethodID(mBundleClass, "putDoubleArray", "(Ljava/lang/String;[D)V");
+
+ ScopedLocalRef<jdoubleArray> arrayRef(mJNIEnv, mJNIEnv->NewDoubleArray(value.size()));
+ mJNIEnv->SetDoubleArrayRegion(arrayRef.get(), 0, value.size(), &value[0]);
+ mJNIEnv->CallVoidMethod(mBundle, putDoubleArrayMethod, keyStringRef.get(), arrayRef.get());
+ return {}; // ok result
+}
+
Result<void> BundleWrapper::putLongArray(const char* key, const std::vector<int64_t>& value) {
ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
if (keyStringRef == nullptr) {
@@ -148,7 +180,20 @@
return {}; // ok result
}
-jobject BundleWrapper::getBundle() {
+Result<void> BundleWrapper::putPersistableBundle(const char* key, const BundleWrapper& value) {
+ jmethodID putPersistableBundleMethod =
+ mJNIEnv->GetMethodID(mBundleClass, "putPersistableBundle",
+ "(Ljava/lang/String;Landroid/os/PersistableBundle;)V");
+ ScopedLocalRef<jstring> keyStringRef(mJNIEnv, mJNIEnv->NewStringUTF(key));
+ if (keyStringRef == nullptr) {
+ return Error() << "Failed to create a string for a key=" << key << " due to OOM error";
+ }
+ mJNIEnv->CallVoidMethod(mBundle, putPersistableBundleMethod, keyStringRef.get(),
+ value.getBundle());
+ return {}; // ok result
+}
+
+jobject BundleWrapper::getBundle() const {
return mBundle;
}
diff --git a/packages/ScriptExecutor/src/BundleWrapper.h b/packages/ScriptExecutor/src/BundleWrapper.h
index a949108..e7473d8 100644
--- a/packages/ScriptExecutor/src/BundleWrapper.h
+++ b/packages/ScriptExecutor/src/BundleWrapper.h
@@ -45,11 +45,15 @@
::android::base::Result<void> putLong(const char* key, int64_t value);
::android::base::Result<void> putDouble(const char* key, double value);
::android::base::Result<void> putString(const char* key, const char* value);
+ ::android::base::Result<void> putBooleanArray(const char* key,
+ const std::vector<unsigned char>& value);
+ ::android::base::Result<void> putDoubleArray(const char* key, const std::vector<double>& value);
::android::base::Result<void> putLongArray(const char* key, const std::vector<int64_t>& value);
::android::base::Result<void> putStringArray(const char* key,
const std::vector<std::string>& value);
+ ::android::base::Result<void> putPersistableBundle(const char* key, const BundleWrapper& value);
- jobject getBundle();
+ jobject getBundle() const;
private:
// The class asks Java to create PersistableBundle object and stores the reference.
diff --git a/packages/ScriptExecutor/src/JniUtils.cpp b/packages/ScriptExecutor/src/JniUtils.cpp
index 62467f5..119debd 100644
--- a/packages/ScriptExecutor/src/JniUtils.cpp
+++ b/packages/ScriptExecutor/src/JniUtils.cpp
@@ -23,6 +23,9 @@
namespace car {
namespace scriptexecutor {
+// TODO(b/199415783): Revisit the topic of limits to potentially move it to standalone file.
+constexpr int MAX_ARRAY_SIZE = 1000;
+
void pushBundleToLuaTable(JNIEnv* env, lua_State* lua, jobject bundle) {
lua_newtable(lua);
// null bundle object is allowed. We will treat it as an empty table.
@@ -52,12 +55,11 @@
ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
ScopedLocalRef<jclass> numberClass(env, env->FindClass("java/lang/Number"));
ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
+ ScopedLocalRef<jclass> booleanArrayClass(env, env->FindClass("[Z"));
ScopedLocalRef<jclass> intArrayClass(env, env->FindClass("[I"));
ScopedLocalRef<jclass> longArrayClass(env, env->FindClass("[J"));
ScopedLocalRef<jclass> doubleArrayClass(env, env->FindClass("[D"));
ScopedLocalRef<jclass> stringArrayClass(env, env->FindClass("[Ljava/lang/String;"));
- // TODO(b/188816922): Handle more types such as float and integer arrays,
- // and perhaps nested Bundles.
jmethodID getMethod = env->GetMethodID(persistableBundleClass.get(), "get",
"(Ljava/lang/String;)Ljava/lang/Object;");
@@ -97,6 +99,23 @@
env->GetStringUTFChars(static_cast<jstring>(value.get()), nullptr);
lua_pushstring(lua, rawStringValue);
env->ReleaseStringUTFChars(static_cast<jstring>(value.get()), rawStringValue);
+ } else if (env->IsInstanceOf(value.get(), booleanArrayClass.get())) {
+ jbooleanArray booleanArray = static_cast<jbooleanArray>(value.get());
+ const auto kLength = env->GetArrayLength(booleanArray);
+ // Arrays are represented as a table of sequential elements in Lua.
+ // We are creating a nested table to represent this array. We specify number of elements
+ // in the Java array to preallocate memory accordingly.
+ lua_createtable(lua, kLength, 0);
+ jboolean* rawBooleanArray = env->GetBooleanArrayElements(booleanArray, nullptr);
+ // Fills in the table at stack idx -2 with key value pairs, where key is a
+ // Lua index and value is an integer from the long array at that index
+ for (int i = 0; i < kLength; i++) {
+ lua_pushboolean(lua, rawBooleanArray[i]);
+ lua_rawseti(lua, /* idx= */ -2,
+ i + 1); // lua index starts from 1
+ }
+ // JNI_ABORT is used because we do not need to copy back elements.
+ env->ReleaseBooleanArrayElements(booleanArray, rawBooleanArray, JNI_ABORT);
} else if (env->IsInstanceOf(value.get(), intArrayClass.get())) {
jintArray intArray = static_cast<jintArray>(value.get());
const auto kLength = env->GetArrayLength(intArray);
@@ -167,6 +186,11 @@
// lua index starts from 1
lua_rawseti(lua, /* idx= */ -2, i + 1);
}
+ } else if (env->IsInstanceOf(value.get(), persistableBundleClass.get())) {
+ jobject bundle = static_cast<jobject>(value.get());
+ // After this call, the lua stack will have 1 new item at the top of the stack: a table
+ // representing the PersistableBundle
+ pushBundleToLuaTable(env, lua, bundle);
} else {
// Other types are not implemented yet, skipping.
continue;
@@ -180,6 +204,178 @@
}
}
+void pushBundleListToLuaTable(JNIEnv* env, lua_State* lua, jobject bundleList) {
+ // Creates a new table as the encompassing array to contain the converted bundles.
+ // Pushed to top of stack.
+ lua_newtable(lua);
+
+ ScopedLocalRef<jclass> listClass(env, env->FindClass("java/util/List"));
+ jmethodID sizeMethod = env->GetMethodID(listClass.get(), "size", "()I");
+ jmethodID getMethod = env->GetMethodID(listClass.get(), "get", "(I)Ljava/lang/Object;");
+
+ const auto listSize = env->CallIntMethod(bundleList, sizeMethod);
+ // For each bundle in the bundleList set a converted Lua table into the table array.
+ for (int i = 0; i < listSize; i++) {
+ // Push to stack the index at which the next Lua table will be at. Lua index start at 1.
+ lua_pushnumber(lua, i + 1);
+ // Convert the bundle at i into Lua table and push to top of stack.
+ pushBundleToLuaTable(env, lua, env->CallObjectMethod(bundleList, getMethod, i));
+ // table[k] = v, table should be at the given index (-3), and expects v the value to be
+ // at the top of the stack, and k the key to be just below the top.
+ lua_settable(lua, /* idx= */ -3);
+ }
+}
+
+Result<void> convertLuaTableToBundle(JNIEnv* env, lua_State* lua, BundleWrapper* bundleWrapper) {
+ // Iterate over Lua table which is expected to be at the top of Lua stack.
+ // lua_next call pops the key from the top of the stack and finds the next
+ // key-value pair. It returns 0 if the next pair was not found.
+ // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
+ lua_pushnil(lua); // First key is a null value, at index -1
+ while (lua_next(lua, /* table index = */ -2) != 0) {
+ // 'key' is at index -2 and 'value' is at index -1
+ // -1 index is the top of the stack.
+ // remove 'value' and keep 'key' for next iteration
+ // Process each key-value depending on a type and push it to Java PersistableBundle.
+ // TODO(b/199531928): Consider putting limits on key sizes as well.
+ const char* key = lua_tostring(lua, /* index = */ -2);
+ Result<void> bundleInsertionResult;
+ if (lua_isboolean(lua, /* index = */ -1)) {
+ bundleInsertionResult =
+ bundleWrapper->putBoolean(key,
+ static_cast<bool>(
+ lua_toboolean(lua, /* index = */ -1)));
+ } else if (lua_isinteger(lua, /* index = */ -1)) {
+ bundleInsertionResult =
+ bundleWrapper->putLong(key,
+ static_cast<int64_t>(
+ lua_tointeger(lua, /* index = */ -1)));
+ } else if (lua_isnumber(lua, /* index = */ -1)) {
+ bundleInsertionResult =
+ bundleWrapper->putDouble(key,
+ static_cast<double>(
+ lua_tonumber(lua, /* index = */ -1)));
+ } else if (lua_isstring(lua, /* index = */ -1)) {
+ // TODO(b/199415783): We need to have a limit on how long these strings could be.
+ bundleInsertionResult =
+ bundleWrapper->putString(key, lua_tostring(lua, /* index = */ -1));
+ } else if (lua_istable(lua, /* index =*/-1) && lua_rawlen(lua, -1) > 0) {
+ // Lua uses tables to represent arrays and PersistableBundles.
+ // If lua_rawlen is greater than 0, this table is a sequence, which means it is an
+ // array.
+
+ // TODO(b/199438375): Document to users that we expect tables to be either only indexed
+ // or keyed but not both. If the table contains consecutively indexed values starting
+ // from 1, we will treat it as an array. lua_rawlen call returns the size of the indexed
+ // part. We copy this part into an array, but any keyed values in this table are
+ // ignored. There is a test that documents this current behavior. If a user wants a
+ // nested table to be represented by a PersistableBundle object, they must make sure
+ // that the nested table does not contain indexed data, including no key=1.
+ const auto kTableLength = lua_rawlen(lua, -1);
+ if (kTableLength > MAX_ARRAY_SIZE) {
+ return Error()
+ << "Returned table " << key << " exceeds maximum allowed size of "
+ << MAX_ARRAY_SIZE
+ << " elements. This key-value cannot be unpacked successfully. This error "
+ "is unrecoverable.";
+ }
+
+ std::vector<unsigned char> boolArray;
+ std::vector<double> doubleArray;
+ std::vector<int64_t> longArray;
+ std::vector<std::string> stringArray;
+ int originalLuaType = LUA_TNIL;
+ for (int i = 0; i < kTableLength; i++) {
+ lua_rawgeti(lua, -1, i + 1);
+ // Lua allows arrays to have values of varying type. We need to force all Lua
+ // arrays to stick to single type within the same array. We use the first value
+ // in the array to determine the type of all values in the array that follow
+ // after. If the second, third, etc element of the array does not match the type
+ // of the first element we stop the extraction and return an error via a
+ // callback.
+ if (i == 0) {
+ originalLuaType = lua_type(lua, /* index = */ -1);
+ }
+ int currentType = lua_type(lua, /* index= */ -1);
+ if (currentType != originalLuaType) {
+ return Error()
+ << "Returned Lua arrays must have elements of the same type. Returned "
+ "table with key="
+ << key << " has the first element of type=" << originalLuaType
+ << ", but the element at index=" << i + 1 << " has type=" << currentType
+ << ". Integer type codes are defined in lua.h file. This error is "
+ "unrecoverable.";
+ }
+ switch (currentType) {
+ case LUA_TBOOLEAN:
+ boolArray.push_back(
+ static_cast<unsigned char>(lua_toboolean(lua, /* index = */ -1)));
+ break;
+ case LUA_TNUMBER:
+ if (lua_isinteger(lua, /* index = */ -1)) {
+ longArray.push_back(lua_tointeger(lua, /* index = */ -1));
+ } else {
+ doubleArray.push_back(lua_tonumber(lua, /* index = */ -1));
+ }
+ break;
+ case LUA_TSTRING:
+ // TODO(b/200833728): Investigate optimizations to minimize string
+ // copying. For example, populate JNI object array one element at a
+ // time, as we go.
+ stringArray.push_back(lua_tostring(lua, /* index = */ -1));
+ break;
+ default:
+ return Error() << "Returned value for key=" << key
+ << " is an array with values of type="
+ << lua_typename(lua, lua_type(lua, /* index = */ -1))
+ << ", which is not supported yet.";
+ }
+ lua_pop(lua, 1);
+ }
+ switch (originalLuaType) {
+ case LUA_TBOOLEAN:
+ bundleInsertionResult = bundleWrapper->putBooleanArray(key, boolArray);
+ break;
+ case LUA_TNUMBER:
+ if (longArray.size() > 0) {
+ bundleInsertionResult = bundleWrapper->putLongArray(key, longArray);
+ } else {
+ bundleInsertionResult = bundleWrapper->putDoubleArray(key, doubleArray);
+ }
+ break;
+ case LUA_TSTRING:
+ bundleInsertionResult = bundleWrapper->putStringArray(key, stringArray);
+ break;
+ }
+ } else if (lua_istable(lua, /* index =*/-1)) {
+ // If the Lua table is not a sequence, i.e., it is a table with string keys, then it is
+ // a PersistableBundle
+ BundleWrapper nestedBundleWrapper(env);
+ // After this line, the Lua stack is unchanged, so the top of the stack is still a
+ // table, but the nestedBundleWrapper will be populated
+ const auto status = convertLuaTableToBundle(env, lua, &nestedBundleWrapper);
+ if (!status.ok()) {
+ return Error() << "Failed to parse nested tables into nested PersistableBundles";
+ }
+ bundleInsertionResult = bundleWrapper->putPersistableBundle(key, nestedBundleWrapper);
+ } else {
+ return Error() << "key=" << key << " has a Lua type="
+ << lua_typename(lua, lua_type(lua, /* index = */ -1))
+ << ", which is not supported yet.";
+ }
+ // Pop value from the stack, keep the key for the next iteration.
+ lua_pop(lua, 1);
+ // The key is at index -1, the table is at index -2 now.
+
+ // Check if insertion of the current key-value into the bundle was successful. If not,
+ // fail-fast out of this extraction routine.
+ if (!bundleInsertionResult.ok()) {
+ return bundleInsertionResult;
+ }
+ }
+ return {}; // ok result
+}
+
} // namespace scriptexecutor
} // namespace car
} // namespace android
diff --git a/packages/ScriptExecutor/src/JniUtils.h b/packages/ScriptExecutor/src/JniUtils.h
index 542a91a..2a08217 100644
--- a/packages/ScriptExecutor/src/JniUtils.h
+++ b/packages/ScriptExecutor/src/JniUtils.h
@@ -22,6 +22,8 @@
#include "lua.h"
}
+#include "BundleWrapper.h"
+
#include <android-base/result.h>
namespace com {
@@ -29,6 +31,9 @@
namespace car {
namespace scriptexecutor {
+using ::android::base::Error;
+using ::android::base::Result;
+
// Helper function which takes android.os.Bundle object in "bundle" argument
// and converts it to Lua table on top of Lua stack. All key-value pairs are
// converted to the corresponding key-value pairs of the Lua table as long as
@@ -36,6 +41,28 @@
// integer, double and String types in Java.
void pushBundleToLuaTable(JNIEnv* env, lua_State* lua, jobject bundle);
+// Helper function that takes list of android.os.Bundle object in "bundleList"
+// argument and converts it to Lua table on top of the Lua stack. The Lua table
+// will be an array of converted android.os.Bundle objects in Lua table form,
+// each having the key-value pairs as converted by pushBundleToLuaTable.
+void pushBundleListToLuaTable(JNIEnv* env, lua_State* lua, jobject bundleList);
+
+// Helper function that goes over Lua table fields one by one and populates PersistableBundle
+// object wrapped in BundleWrapper.
+// It is assumed that Lua table is located on top of the Lua stack. There could be other
+// items in the stack, this function will not touch them.
+//
+// Returns false if the conversion encountered unrecoverable error.
+// Otherwise, returns true for success.
+//
+// If the function succeeds, the stack should be unchanged.
+// In case of an error, there is no need to pop elements or clean the stack. When Lua calls C,
+// the stack used to pass data between Lua and C is private for each call. According to
+// https://www.lua.org/pil/26.1.html, after C function returns back to Lua, Lua
+// removes everything that is in the stack below the returned results.
+// TODO(b/200849134): Refactor this function.
+Result<void> convertLuaTableToBundle(JNIEnv* env, lua_State* lua, BundleWrapper* bundleWrapper);
+
} // namespace scriptexecutor
} // namespace car
} // namespace android
diff --git a/packages/ScriptExecutor/src/LuaEngine.cpp b/packages/ScriptExecutor/src/LuaEngine.cpp
index 3a5daf4..e7cf654 100644
--- a/packages/ScriptExecutor/src/LuaEngine.cpp
+++ b/packages/ScriptExecutor/src/LuaEngine.cpp
@@ -17,6 +17,8 @@
#include "LuaEngine.h"
#include "BundleWrapper.h"
+#include "JniUtils.h"
+#include "jni.h"
#include <android-base/logging.h>
@@ -36,9 +38,6 @@
namespace car {
namespace scriptexecutor {
-using ::android::base::Error;
-using ::android::base::Result;
-
namespace {
enum LuaNumReturnedResults {
@@ -48,156 +47,6 @@
// Prefix for logging messages coming from lua script.
const char kLuaLogTag[] = "LUA: ";
-// TODO(b/199415783): Revisit the topic of limits to potentially move it to standalone file.
-constexpr int MAX_ARRAY_SIZE = 1000;
-
-// Helper method that goes over Lua table fields one by one and populates PersistableBundle
-// object wrapped in BundleWrapper.
-// It is assumed that Lua table is located on top of the Lua stack. There could be other
-// items in the stack, this function will not touch them.
-//
-// Returns false if the conversion encountered unrecoverable error.
-// Otherwise, returns true for success.
-//
-// If the function succeeds, the stack should be unchanged.
-// In case of an error, there is no need to pop elements or clean the stack. When Lua calls C,
-// the stack used to pass data between Lua and C is private for each call. According to
-// https://www.lua.org/pil/26.1.html, after C function returns back to Lua, Lua
-// removes everything that is in the stack below the returned results.
-// TODO(b/200849134): Refactor this function.
-Result<void> convertLuaTableToBundle(lua_State* lua, BundleWrapper* bundleWrapper) {
- // Iterate over Lua table which is expected to be at the top of Lua stack.
- // lua_next call pops the key from the top of the stack and finds the next
- // key-value pair. It returns 0 if the next pair was not found.
- // More on lua_next in: https://www.lua.org/manual/5.3/manual.html#lua_next
- lua_pushnil(lua); // First key is a null value, at index -1
- while (lua_next(lua, /* table index = */ -2) != 0) {
- // 'key' is at index -2 and 'value' is at index -1
- // -1 index is the top of the stack.
- // remove 'value' and keep 'key' for next iteration
- // Process each key-value depending on a type and push it to Java PersistableBundle.
- // TODO(b/199531928): Consider putting limits on key sizes as well.
- const char* key = lua_tostring(lua, /* index = */ -2);
- Result<void> bundleInsertionResult;
- if (lua_isboolean(lua, /* index = */ -1)) {
- bundleInsertionResult =
- bundleWrapper->putBoolean(key,
- static_cast<bool>(
- lua_toboolean(lua, /* index = */ -1)));
- } else if (lua_isinteger(lua, /* index = */ -1)) {
- bundleInsertionResult =
- bundleWrapper->putLong(key,
- static_cast<int64_t>(
- lua_tointeger(lua, /* index = */ -1)));
- } else if (lua_isnumber(lua, /* index = */ -1)) {
- bundleInsertionResult =
- bundleWrapper->putDouble(key,
- static_cast<double>(
- lua_tonumber(lua, /* index = */ -1)));
- } else if (lua_isstring(lua, /* index = */ -1)) {
- // TODO(b/199415783): We need to have a limit on how long these strings could be.
- bundleInsertionResult =
- bundleWrapper->putString(key, lua_tostring(lua, /* index = */ -1));
- } else if (lua_istable(lua, /* index =*/-1)) {
- // Lua uses tables to represent an array.
-
- // TODO(b/199438375): Document to users that we expect tables to be either only indexed
- // or keyed but not both. If the table contains consecutively indexed values starting
- // from 1, we will treat it as an array. lua_rawlen call returns the size of the indexed
- // part. We copy this part into an array, but any keyed values in this table are
- // ignored. There is a test that documents this current behavior. If a user wants a
- // nested table to be represented by a PersistableBundle object, they must make sure
- // that the nested table does not contain indexed data, including no key=1.
- const auto kTableLength = lua_rawlen(lua, -1);
- if (kTableLength > MAX_ARRAY_SIZE) {
- return Error()
- << "Returned table " << key << " exceeds maximum allowed size of "
- << MAX_ARRAY_SIZE
- << " elements. This key-value cannot be unpacked successfully. This error "
- "is unrecoverable.";
- }
- if (kTableLength <= 0) {
- return Error() << "A value with key=" << key
- << " appears to be a nested table that does not represent an array "
- "of data. "
- "Such nested tables are not supported yet. This script error is "
- "unrecoverable.";
- }
-
- std::vector<int64_t> longArray;
- std::vector<std::string> stringArray;
- int originalLuaType = LUA_TNIL;
- for (int i = 0; i < kTableLength; i++) {
- lua_rawgeti(lua, -1, i + 1);
- // Lua allows arrays to have values of varying type. We need to force all Lua
- // arrays to stick to single type within the same array. We use the first value
- // in the array to determine the type of all values in the array that follow
- // after. If the second, third, etc element of the array does not match the type
- // of the first element we stop the extraction and return an error via a
- // callback.
- if (i == 0) {
- originalLuaType = lua_type(lua, /* index = */ -1);
- }
- int currentType = lua_type(lua, /* index= */ -1);
- if (currentType != originalLuaType) {
- return Error()
- << "Returned Lua arrays must have elements of the same type. Returned "
- "table with key="
- << key << " has the first element of type=" << originalLuaType
- << ", but the element at index=" << i + 1 << " has type=" << currentType
- << ". Integer type codes are defined in lua.h file. This error is "
- "unrecoverable.";
- }
- switch (currentType) {
- case LUA_TNUMBER:
- if (!lua_isinteger(lua, /* index = */ -1)) {
- return Error() << "Returned value for key=" << key
- << " contains a floating number array, which is not "
- "supported yet.";
- } else {
- longArray.push_back(lua_tointeger(lua, /* index = */ -1));
- }
- break;
- case LUA_TSTRING:
- // TODO(b/200833728): Investigate optimizations to minimize string
- // copying. For example, populate JNI object array one element at a
- // time, as we go.
- stringArray.push_back(lua_tostring(lua, /* index = */ -1));
- break;
- default:
- return Error() << "Returned value for key=" << key
- << " is an array with values of type="
- << lua_typename(lua, lua_type(lua, /* index = */ -1))
- << ", which is not supported yet.";
- }
- lua_pop(lua, 1);
- }
- switch (originalLuaType) {
- case LUA_TNUMBER:
- bundleInsertionResult = bundleWrapper->putLongArray(key, longArray);
- break;
- case LUA_TSTRING:
- bundleInsertionResult = bundleWrapper->putStringArray(key, stringArray);
- break;
- }
- } else {
- return Error() << "key=" << key << " has a Lua type="
- << lua_typename(lua, lua_type(lua, /* index = */ -1))
- << ", which is not supported yet.";
- }
- // Pop value from the stack, keep the key for the next iteration.
- lua_pop(lua, 1);
- // The key is at index -1, the table is at index -2 now.
-
- // Check if insertion of the current key-value into the bundle was successful. If not,
- // fail-fast out of this extraction routine.
- if (!bundleInsertionResult.ok()) {
- return bundleInsertionResult;
- }
- }
- return {}; // ok result
-}
-
} // namespace
ScriptExecutorListener* LuaEngine::sListener = nullptr;
@@ -313,7 +162,7 @@
// Helper object to create and populate Java PersistableBundle object.
BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
- const auto status = convertLuaTableToBundle(lua, &bundleWrapper);
+ const auto status = convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bundleWrapper);
if (!status.ok()) {
sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
// We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -341,7 +190,7 @@
// Helper object to create and populate Java PersistableBundle object.
BundleWrapper bundleWrapper(sListener->getCurrentJNIEnv());
- const auto status = convertLuaTableToBundle(lua, &bundleWrapper);
+ const auto status = convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bundleWrapper);
if (!status.ok()) {
sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
// We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -390,7 +239,8 @@
// object.
BundleWrapper topBundleWrapper(sListener->getCurrentJNIEnv());
// If the helper function succeeds, it should not change the stack
- const auto status = convertLuaTableToBundle(lua, &topBundleWrapper);
+ const auto status =
+ convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &topBundleWrapper);
if (!status.ok()) {
sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, status.error().message().c_str(), "");
// We explicitly must tell Lua how many results we return, which is 0 in this case.
@@ -420,7 +270,8 @@
// process the report
BundleWrapper bottomBundleWrapper(sListener->getCurrentJNIEnv());
- const auto statusBottom = convertLuaTableToBundle(lua, &bottomBundleWrapper);
+ const auto statusBottom =
+ convertLuaTableToBundle(sListener->getCurrentJNIEnv(), lua, &bottomBundleWrapper);
if (!statusBottom.ok()) {
sListener->onError(ERROR_TYPE_LUA_SCRIPT_ERROR, statusBottom.error().message().c_str(), "");
// We explicitly must tell Lua how many results we return, which is 0 in this case.
diff --git a/packages/ScriptExecutor/src/ScriptExecutorJni.cpp b/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
index d8ddd55..7a38ab8 100644
--- a/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
+++ b/packages/ScriptExecutor/src/ScriptExecutorJni.cpp
@@ -67,7 +67,7 @@
// Step 6: Attempt to run the provided function.
JNIEXPORT void JNICALL Java_com_android_car_scriptexecutor_ScriptExecutor_nativeInvokeScript(
JNIEnv* env, jobject object, jlong luaEnginePtr, jstring scriptBody, jstring functionName,
- jobject publishedData, jobject savedState, jobject listener) {
+ jobject publishedData, jobject bundleList, jobject savedState, jobject listener) {
if (!luaEnginePtr) {
env->FatalError("luaEnginePtr parameter cannot be nil");
}
@@ -106,8 +106,13 @@
return;
}
- // Unpack bundle in publishedData, convert to Lua table and push it to Lua stack.
- pushBundleToLuaTable(env, engine->getLuaState(), publishedData);
+ if (bundleList != nullptr) {
+ // Unpack bundle in bundleList, convert to Lua array of tables and push it to Lua stack.
+ pushBundleListToLuaTable(env, engine->getLuaState(), bundleList);
+ } else {
+ // Unpack bundle in publishedData, convert to Lua table and push it to Lua stack.
+ pushBundleToLuaTable(env, engine->getLuaState(), publishedData);
+ }
// Unpack bundle in savedState, convert to Lua table and push it to Lua
// stack.
diff --git a/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java b/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
index 362005e..aea6f3f 100644
--- a/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
+++ b/packages/ScriptExecutor/src/com/android/car/scriptexecutor/ScriptExecutor.java
@@ -29,11 +29,14 @@
import android.os.UserHandle;
import android.util.Log;
+import com.android.car.internal.LargeParcelable;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
/**
* Executes Lua code in an isolated process with provided source code
@@ -59,7 +62,7 @@
ensureCallerIsSystem();
mNativeHandler.post(() ->
nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, publishedData,
- savedState, listener));
+ null, savedState, listener));
}
@Override
@@ -87,9 +90,22 @@
}
nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, publishedData,
- savedState, listener);
+ null, savedState, listener);
});
}
+
+ @Override
+ public void invokeScriptForBundleList(String scriptBody, String functionName,
+ BundleList bundleList, PersistableBundle savedState,
+ IScriptExecutorListener listener) throws SecurityException {
+ ensureCallerIsSystem();
+ BundleList reconstBundles =
+ (BundleList) LargeParcelable.reconstructStableAIDLParcelable(
+ bundleList, /*keepSharedMemory=*/false);
+ mNativeHandler.post(() ->
+ nativeInvokeScript(mLuaEnginePtr, scriptBody, functionName, null,
+ reconstBundles.bundles, savedState, listener));
+ }
}
private IScriptExecutorImpl mScriptExecutorBinder;
@@ -147,12 +163,14 @@
* invoked.
* @param functionName the name of the function to execute.
* @param publishedData input data provided by the source which the function handles.
+ * @param bundleList input data list provided by the source which the function handles.
* @param savedState key-value pairs preserved from the previous invocation of the function.
- * @param listener callback for the sandboxed environent to report back script execution
+ * @param listener callback for the sandboxed environment to report back script execution
* results
* and errors.
*/
private native void nativeInvokeScript(long luaEnginePtr, String scriptBody,
- String functionName, PersistableBundle publishedData, PersistableBundle savedState,
+ String functionName, PersistableBundle publishedData,
+ List<PersistableBundle> bundleList, PersistableBundle savedState,
IScriptExecutorListener listener);
}
diff --git a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
index 68bc2b1..8ae1f27 100644
--- a/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
+++ b/packages/ScriptExecutor/tests/functional/src/com/android/car/scriptexecutortest/functional/ScriptExecutorFunctionalTest.java
@@ -164,21 +164,51 @@
}
@Test
- public void invokeScript_skipsUnsupportedNestedTables()
+ public void invokeScript_supportsNestedTables()
throws RemoteException, InterruptedException {
String script =
"function nested(data, state)\n"
+ " result = {string=\"hello\", boolean=true, integer=1, number=1.1}\n"
- + " result.nested_table = {x=0, y=0}\n"
+ + " result.nested_table = {x=10, y=30}\n"
+ " on_success(result)\n"
+ "end\n";
runScriptAndWaitForResponse(script, "nested", mEmptyPublishedData, mEmptyIterimResult);
// Verify that expected error is received.
- assertThat(mListener.mErrorType)
- .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
- assertThat(mListener.mMessage).contains("nested tables are not supported");
+ assertThat(mListener.mInterimResult.size()).isEqualTo(5);
+ PersistableBundle nestedBundle = mListener.mInterimResult.getPersistableBundle(
+ "nested_table");
+ assertThat(nestedBundle).isNotNull();
+ assertThat(nestedBundle.getLong("x")).isEqualTo(10);
+ assertThat(nestedBundle.getLong("y")).isEqualTo(30);
+ }
+
+ @Test
+ public void invokeScript_supportsDeeplyNestedTables()
+ throws RemoteException, InterruptedException {
+ String script =
+ "function nested(data, state)\n"
+ + " local result = {}\n"
+ + " result.nested_table = {x=10, y=30}\n"
+ + " result.nested_table.second_nested_table = {z=100}\n"
+ + " on_success(result)\n"
+ + "end\n";
+
+ runScriptAndWaitForResponse(script, "nested", mEmptyPublishedData, mEmptyIterimResult);
+
+ // Verify that expected error is received.
+ assertThat(mListener.mInterimResult.size()).isEqualTo(1);
+ PersistableBundle nestedBundle = mListener.mInterimResult.getPersistableBundle(
+ "nested_table");
+ assertThat(nestedBundle).isNotNull();
+ assertThat(nestedBundle.size()).isEqualTo(3);
+ assertThat(nestedBundle.getLong("x")).isEqualTo(10);
+ assertThat(nestedBundle.getLong("y")).isEqualTo(30);
+ PersistableBundle secondNestedBundle = nestedBundle.getPersistableBundle(
+ "second_nested_table");
+ assertThat(secondNestedBundle.size()).isEqualTo(1);
+ assertThat(secondNestedBundle.getLong("z")).isEqualTo(100);
}
@Test
@@ -254,16 +284,22 @@
String script =
"function arrays(data, state)\n"
+ " result = {}\n"
+ + " result.boolean_array = state.boolean_array\n"
+ + " result.double_array = state.double_array\n"
+ " result.int_array = state.int_array\n"
+ " result.long_array = state.long_array\n"
+ " result.string_array = state.string_array\n"
+ " on_success(result)\n"
+ "end\n";
PersistableBundle previousState = new PersistableBundle();
+ boolean[] boolean_array = new boolean[] {true, true, false};
+ double[] double_array = new double[] {1.5, 2.222};
int[] int_array = new int[] {1, 2};
long[] int_array_in_long = new long[] {1, 2};
long[] long_array = new long[] {1, 2, 3};
String[] string_array = new String[] {"one", "two", "three"};
+ previousState.putBooleanArray("boolean_array", boolean_array);
+ previousState.putDoubleArray("double_array", double_array);
previousState.putIntArray("int_array", int_array);
previousState.putLongArray("long_array", long_array);
previousState.putStringArray("string_array", string_array);
@@ -271,9 +307,12 @@
runScriptAndWaitForResponse(script, "arrays", mEmptyPublishedData, previousState);
// Verify that keys are preserved but the values are modified as expected.
- assertThat(mListener.mInterimResult.size()).isEqualTo(3);
+ assertThat(mListener.mInterimResult.size()).isEqualTo(5);
// Lua has only one lua_Integer. Here Java long is used to represent it when data is
// transferred from Lua to CarTelemetryService.
+ assertThat(mListener.mInterimResult.getBooleanArray("boolean_array"))
+ .isEqualTo(boolean_array);
+ assertThat(mListener.mInterimResult.getDoubleArray("double_array")).isEqualTo(double_array);
assertThat(mListener.mInterimResult.getLongArray("int_array")).isEqualTo(int_array_in_long);
assertThat(mListener.mInterimResult.getLongArray("long_array")).isEqualTo(long_array);
assertThat(mListener.mInterimResult.getStringArray("string_array")).isEqualTo(string_array);
@@ -856,52 +895,6 @@
}
@Test
- public void invokeScript_returnedFloatingArraysNotSupported()
- throws RemoteException, InterruptedException {
- // Verifies that we do not support return values that contain floating number arrays.
- String script =
- "function floating_point_arrays(data, state)\n"
- + " array = {}\n"
- + " array[0] = 1.1\n"
- + " array[1] = 1.2\n"
- + " result = {data = array}\n"
- + " on_success(result)\n"
- + "end\n";
-
- runScriptAndWaitForResponse(
- script, "floating_point_arrays", mEmptyPublishedData, mEmptyIterimResult);
-
- // Verify that the expected error is received.
- assertThat(mListener.mErrorType)
- .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
- assertThat(mListener.mMessage)
- .contains("a floating number array, which is not supported yet");
- }
-
- @Test
- public void invokeScript_returnedBooleanArraysNotSupported()
- throws RemoteException, InterruptedException {
- // Verifies that we do not yet support return values that contain boolean arrays.
- String script =
- "function array_of_booleans(data, state)\n"
- + " array = {}\n"
- + " array[0] = false\n"
- + " array[1] = true\n"
- + " result = {data = array}\n"
- + " on_success(result)\n"
- + "end\n";
-
- runScriptAndWaitForResponse(
- script, "array_of_booleans", mEmptyPublishedData, mEmptyIterimResult);
-
- // Verify that the expected error is received.
- assertThat(mListener.mErrorType)
- .isEqualTo(IScriptExecutorListener.ERROR_TYPE_LUA_SCRIPT_ERROR);
- assertThat(mListener.mMessage)
- .contains("is an array with values of type=boolean, which is not supported yet");
- }
-
- @Test
public void invokeScript_onMetricsReport_returnsReport() throws Exception {
String returnFinalResultScript =
"function script_completes(data, state)\n"
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
index 7a7404f..3e4f33e 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTest.java
@@ -26,6 +26,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(JUnit4.class)
public final class JniUtilsTest {
@@ -35,17 +38,22 @@
private static final String INT_KEY = "int_key";
private static final String STRING_KEY = "string_key";
private static final String NUMBER_KEY = "number_key";
+ private static final String BOOLEAN_ARRAY_KEY = "boolean_array_key";
private static final String INT_ARRAY_KEY = "int_array_key";
private static final String LONG_ARRAY_KEY = "long_array_key";
private static final String DOUBLE_ARRAY_KEY = "double_array_key";
+ private static final String PERSISTABLE_BUNDLE_KEY = "persistable_bundle_key";
private static final boolean BOOLEAN_VALUE = true;
private static final double NUMBER_VALUE = 0.1;
private static final int INT_VALUE = 10;
+ private static final int INT_VALUE_2 = 20;
private static final String STRING_VALUE = "test";
+ private static final boolean[] BOOLEAN_ARRAY_VALUE = new boolean[]{true, false, true};
private static final int[] INT_ARRAY_VALUE = new int[]{1, 2, 3};
private static final long[] LONG_ARRAY_VALUE = new long[]{1, 2, 3, 4};
private static final double[] DOUBLE_ARRAY_VALUE = new double[]{1.1d, 2.2d, 3.3d, 4.4d};
+ private static final PersistableBundle PERSISTABLE_BUNDLE_VALUE = new PersistableBundle();
// Pointer to Lua Engine instantiated in native space.
private long mLuaEnginePtr = 0;
@@ -68,6 +76,10 @@
private native void nativePushBundleToLuaTableCaller(
long luaEnginePtr, PersistableBundle bundle);
+ // Invokes pushBundleListToLuaTable native method.
+ private native void nativePushBundleListToLuaTableCaller(
+ long luaEnginePtr, List<PersistableBundle> bundleList);
+
// Creates an instance of LuaEngine on the heap and returns the pointer.
private native long nativeCreateLuaEngine();
@@ -87,6 +99,9 @@
private native boolean nativeHasIntValue(long luaEnginePtr, String key, int value);
+ private native boolean nativeHasBooleanArrayValue(
+ long luaEnginePtr, String key, boolean[] value);
+
private native boolean nativeHasDoubleValue(long luaEnginePtr, String key, double value);
private native boolean nativeHasIntArrayValue(long luaEnginePtr, String key, int[] value);
@@ -95,6 +110,18 @@
private native boolean nativeHasDoubleArrayValue(long luaEnginePtr, String key, double[] value);
+ /*
+ * Checks if the key maps to a Lua table/PersistableBundle, and checks if the PersistableBundle
+ * has the string representation equal to the parameter {@code expected}.
+ */
+ private native boolean nativeHasPersistableBundleOfStringValue(
+ long luaEnginePtr, String key, String expected);
+
+ private native boolean nativeHasNumberOfTables(long luaEnginePtr, int num);
+
+ private native boolean nativeHasTableAtIndexWithIntValue(
+ long luaEnginePtr, int index, String key, int value);
+
@Test
public void pushBundleToLuaTable_nullBundleMakesEmptyLuaTable() {
nativePushBundleToLuaTableCaller(mLuaEnginePtr, null);
@@ -110,6 +137,7 @@
bundle.putInt(INT_KEY, INT_VALUE);
bundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
bundle.putString(STRING_KEY, STRING_VALUE);
+ bundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, PERSISTABLE_BUNDLE_VALUE);
// Invokes the corresponding helper method to convert the bundle
// to Lua table on Lua stack.
@@ -120,6 +148,8 @@
assertThat(nativeHasIntValue(mLuaEnginePtr, INT_KEY, INT_VALUE)).isTrue();
assertThat(nativeHasDoubleValue(mLuaEnginePtr, NUMBER_KEY, NUMBER_VALUE)).isTrue();
assertThat(nativeHasStringValue(mLuaEnginePtr, STRING_KEY, STRING_VALUE)).isTrue();
+ assertThat(nativeHasPersistableBundleOfStringValue(mLuaEnginePtr, PERSISTABLE_BUNDLE_KEY,
+ PERSISTABLE_BUNDLE_VALUE.toString())).isTrue();
}
@Test
@@ -138,6 +168,7 @@
@Test
public void pushBundleToLuaTable_arrays() {
PersistableBundle bundle = new PersistableBundle();
+ bundle.putBooleanArray(BOOLEAN_ARRAY_KEY, BOOLEAN_ARRAY_VALUE);
bundle.putIntArray(INT_ARRAY_KEY, INT_ARRAY_VALUE);
bundle.putLongArray(LONG_ARRAY_KEY, LONG_ARRAY_VALUE);
bundle.putDoubleArray(DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE);
@@ -149,11 +180,50 @@
// Check contents of Lua table.
// Java int and long arrays both end up being arrays of Lua's Integer type,
// which is interpreted as a 8-byte int type.
+ assertThat(nativeHasBooleanArrayValue(
+ mLuaEnginePtr, BOOLEAN_ARRAY_KEY, BOOLEAN_ARRAY_VALUE)).isTrue();
assertThat(nativeHasIntArrayValue(mLuaEnginePtr, INT_ARRAY_KEY, INT_ARRAY_VALUE)).isTrue();
- assertThat(
- nativeHasLongArrayValue(mLuaEnginePtr, LONG_ARRAY_KEY, LONG_ARRAY_VALUE)).isTrue();
- assertThat(
- nativeHasDoubleArrayValue(mLuaEnginePtr, DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE))
+ assertThat(nativeHasLongArrayValue(mLuaEnginePtr, LONG_ARRAY_KEY, LONG_ARRAY_VALUE))
.isTrue();
+ assertThat(nativeHasDoubleArrayValue(mLuaEnginePtr, DOUBLE_ARRAY_KEY, DOUBLE_ARRAY_VALUE))
+ .isTrue();
+ }
+
+ @Test
+ public void pushBundleListToLuaTable_makesArrayOfTables() {
+ PersistableBundle bundle1 = new PersistableBundle();
+ PersistableBundle bundle2 = new PersistableBundle();
+ bundle1.putInt(INT_KEY, INT_VALUE);
+ bundle2.putInt(INT_KEY, INT_VALUE_2);
+ List<PersistableBundle> bundleList = new ArrayList<>();
+ bundleList.add(bundle1);
+ bundleList.add(bundle2);
+
+ nativePushBundleListToLuaTableCaller(mLuaEnginePtr, bundleList);
+
+ assertThat(nativeHasNumberOfTables(mLuaEnginePtr, 2)).isTrue();
+ assertThat(nativeHasTableAtIndexWithIntValue(mLuaEnginePtr, 1, INT_KEY, INT_VALUE))
+ .isTrue();
+ assertThat(nativeHasTableAtIndexWithIntValue(mLuaEnginePtr, 2, INT_KEY, INT_VALUE_2))
+ .isTrue();
+ }
+
+ @Test
+ public void pushBundleToLuaTable_nestedBundle() {
+ PersistableBundle bundle = new PersistableBundle();
+ PersistableBundle nestedBundle = new PersistableBundle();
+ nestedBundle.putInt(INT_KEY, INT_VALUE);
+ nestedBundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
+ nestedBundle.putString(STRING_KEY, STRING_VALUE);
+ nestedBundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, PERSISTABLE_BUNDLE_VALUE);
+ bundle.putPersistableBundle(PERSISTABLE_BUNDLE_KEY, nestedBundle);
+
+ // Invokes the corresponding helper method to convert the bundle
+ // to Lua table on Lua stack.
+ nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+ // Check contents of Lua table/PersistableBundle.
+ assertThat(nativeHasPersistableBundleOfStringValue(
+ mLuaEnginePtr, PERSISTABLE_BUNDLE_KEY, nestedBundle.toString())).isTrue();
}
}
diff --git a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
index 11ae637..5597e50 100644
--- a/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
+++ b/packages/ScriptExecutor/tests/unit/src/com/android/car/scriptexecutortest/unit/JniUtilsTestHelper.cpp
@@ -14,9 +14,11 @@
* limitations under the License.
*/
+#include "BundleWrapper.h"
#include "JniUtils.h"
#include "LuaEngine.h"
#include "jni.h"
+#include "nativehelper/scoped_local_ref.h"
#include <cstdint>
#include <cstring>
@@ -70,6 +72,44 @@
return result;
}
+template <typename T>
+bool hasValidBooleanArray(JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key,
+ T rawInputArray, const int arrayLength) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ scriptexecutor::LuaEngine* engine =
+ reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->getLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_istable(luaState, -1)) {
+ result = false;
+ } else {
+ // First, compare the input and Lua array sizes.
+ const auto kActualLength = lua_rawlen(luaState, -1);
+ if (arrayLength != kActualLength) {
+ // No need to compare further if number of elements in the two arrays are not equal.
+ result = false;
+ } else {
+ // Do element by element comparison.
+ bool is_equal = true;
+ for (int i = 0; i < arrayLength; ++i) {
+ lua_rawgeti(luaState, -1, i + 1);
+ is_equal = lua_isboolean(luaState, /* idx = */ -1) &&
+ lua_toboolean(luaState, /* idx = */ -1) ==
+ static_cast<bool>(rawInputArray[i]);
+ lua_pop(luaState, 1);
+ if (!is_equal) break;
+ }
+ result = is_equal;
+ }
+ }
+ lua_pop(luaState, 1);
+ return result;
+}
+
extern "C" {
#include "lua.h"
@@ -95,6 +135,14 @@
scriptexecutor::pushBundleToLuaTable(env, engine->getLuaState(), bundle);
}
+JNIEXPORT void JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativePushBundleListToLuaTableCaller(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundleList) {
+ scriptexecutor::LuaEngine* engine =
+ reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ scriptexecutor::pushBundleListToLuaTable(env, engine->getLuaState(), bundleList);
+}
+
JNIEXPORT jint JNICALL
Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeGetObjectSize(JNIEnv* env,
jobject object,
@@ -188,6 +236,16 @@
}
JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasBooleanArrayValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jbooleanArray value) {
+ jboolean* rawInputArray = env->GetBooleanArrayElements(value, nullptr);
+ const auto kInputLength = env->GetArrayLength(value);
+ bool result = hasValidBooleanArray(env, object, luaEnginePtr, key, rawInputArray, kInputLength);
+ env->ReleaseBooleanArrayElements(value, rawInputArray, JNI_ABORT);
+ return result;
+}
+
+JNIEXPORT bool JNICALL
Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasIntArrayValue(
JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jintArray value) {
jint* rawInputArray = env->GetIntArrayElements(value, nullptr);
@@ -220,6 +278,85 @@
return result;
}
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasNumberOfTables(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jint num) {
+ scriptexecutor::LuaEngine* engine =
+ reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ auto* luaState = engine->getLuaState();
+ bool result = true;
+ for (int i = 1; i <= num; i++) {
+ lua_pushinteger(luaState, i);
+ lua_gettable(luaState, -2);
+ if (!lua_istable(luaState, -1)) {
+ result = false;
+ }
+ lua_pop(luaState, 1);
+ }
+ return result;
+}
+
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasTableAtIndexWithIntValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jint index, jstring key, jint value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ scriptexecutor::LuaEngine* engine =
+ reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->getLuaState();
+ lua_pushinteger(luaState, index);
+ lua_gettable(luaState, -2);
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isinteger(luaState, -1))
+ result = false;
+ else
+ result = lua_tointeger(luaState, -1) == static_cast<int>(value);
+ lua_pop(luaState, 2);
+ return result;
+}
+
+JNIEXPORT bool JNICALL
+Java_com_android_car_scriptexecutortest_unit_JniUtilsTest_nativeHasPersistableBundleOfStringValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jstring expected) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ scriptexecutor::LuaEngine* engine =
+ reinterpret_cast<scriptexecutor::LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->getLuaState();
+ lua_pushstring(luaState, rawKey);
+ lua_gettable(luaState, -2);
+ // check if the key maps to a value of type table
+ if (!lua_istable(luaState, -1)) {
+ return false;
+ }
+ // convert value (a table) into a PersistableBundle
+ scriptexecutor::BundleWrapper bundleWrapper(env);
+ scriptexecutor::convertLuaTableToBundle(env, luaState, &bundleWrapper);
+ // call PersistableBundle#toString() to compare the string representation with the expected
+ // representation
+ ScopedLocalRef<jclass> persistableBundleClass(env,
+ env->FindClass("android/os/PersistableBundle"));
+ jmethodID toStringMethod =
+ env->GetMethodID(persistableBundleClass.get(), "toString", "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> actual(env,
+ (jstring)env->CallObjectMethod(bundleWrapper.getBundle(),
+ toStringMethod));
+ // convert jstring into c string
+ const char* nativeActualString = env->GetStringUTFChars(actual.get(), nullptr);
+ const char* nativeExpectedString = env->GetStringUTFChars(expected, nullptr);
+
+ // compare actual vs expected
+ int res = strncmp(nativeActualString, nativeExpectedString, strlen(nativeActualString));
+
+ env->ReleaseStringUTFChars(key, rawKey);
+ env->ReleaseStringUTFChars(actual.get(), nativeActualString);
+ env->ReleaseStringUTFChars(expected, nativeExpectedString);
+ return res == 0;
+}
+
} // extern "C"
} // namespace
diff --git a/service-builtin/res/values/strings.xml b/service-builtin/res/values/strings.xml
index e15b970..4ac5e18 100644
--- a/service-builtin/res/values/strings.xml
+++ b/service-builtin/res/values/strings.xml
@@ -80,17 +80,11 @@
<!-- Title of notification shown when an app overuses system resources [CHAR LIMIT=100] -->
<string name="resource_overuse_notification_title"><xliff:g name="app_name" example="Maps">^1</xliff:g> is affecting your system performance</string>
<!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
- <string name="resource_overuse_notification_text_disable_app">Disable app to improve system performance. You can enable the app once again in Settings.</string>
- <!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
- <string name="resource_overuse_notification_text_prioritize_app">Prioritize app to keep using app.</string>
- <!-- Message of notification shown when an app overuses system resources [CHAR LIMIT=NONE] -->
- <string name="resource_overuse_notification_text_uninstall_app">Uninstall app to improve system performance.</string>
+ <string name="resource_overuse_notification_text_disabled_app">This app has been prevented from running in the background. Prioritize app to continue background usage.</string>
<!-- Label for button that will disable the app now [CHAR LIMIT=30] -->
- <string name="resource_overuse_notification_button_disable_app">Disable app</string>
+ <string name="resource_overuse_notification_button_close_app">Close</string>
<!-- Label for button that will redirect user to prioritize app setting [CHAR LIMIT=30] -->
<string name="resource_overuse_notification_button_prioritize_app">Prioritize app</string>
- <!-- Label for button that will redirect user to uninstall app setting [CHAR LIMIT=30] -->
- <string name="resource_overuse_notification_button_uninstall_app">Uninstall app</string>
<!-- Text of the toast shown when the app is disabled [CHAR_LIMIT=100]-->
<string name="resource_overuse_toast_disable_app_now"><xliff:g name="app_name" example="Maps">^1</xliff:g> has been disabled. You can enable it again in Settings.</string>
</resources>
diff --git a/service-builtin/src/com/android/car/CarService.java b/service-builtin/src/com/android/car/CarService.java
index 30f57b9..42c3636 100644
--- a/service-builtin/src/com/android/car/CarService.java
+++ b/service-builtin/src/com/android/car/CarService.java
@@ -18,10 +18,19 @@
import android.content.Intent;
+import com.android.internal.os.BinderInternal;
+
/** Proxy service for CarServciceImpl */
public class CarService extends ServiceProxy {
+
+ // Binder threads are set to 31. system_server is also using 31.
+ // check sMaxBinderThreads in SystemServer.java
+ private static final int MAX_BINDER_THREADS = 31;
+
public CarService() {
super(UpdatablePackageDependency.CAR_SERVICE_IMPL_CLASS);
+ // Increase the number of binder threads in car service
+ BinderInternal.setMaxThreads(MAX_BINDER_THREADS);
}
@Override
diff --git a/service-builtin/src/com/android/car/admin/NotificationHelper.java b/service-builtin/src/com/android/car/admin/NotificationHelper.java
index 9521cad..54a802b 100644
--- a/service-builtin/src/com/android/car/admin/NotificationHelper.java
+++ b/service-builtin/src/com/android/car/admin/NotificationHelper.java
@@ -59,8 +59,6 @@
"com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
public static final String CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS =
"com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
- public static final String CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP =
- "com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
public static final String CAR_SERVICE_PACKAGE_NAME = "com.android.car";
@VisibleForTesting
public static final String CHANNEL_ID_DEFAULT = "channel_id_default";
@@ -229,20 +227,12 @@
context.getSystemService(NotificationManager.class);
CharSequence titleTemplate = context.getText(R.string.resource_overuse_notification_title);
- String textPrioritizeApp =
- context.getString(R.string.resource_overuse_notification_text_prioritize_app);
- String textDisableApp =
- context.getString(R.string.resource_overuse_notification_text_disable_app) + " "
- + textPrioritizeApp;
- String textUninstallApp =
- context.getString(R.string.resource_overuse_notification_text_uninstall_app) + " "
- + textPrioritizeApp;
+ String textDisabledApp =
+ context.getString(R.string.resource_overuse_notification_text_disabled_app);
String actionTitlePrioritizeApp =
context.getString(R.string.resource_overuse_notification_button_prioritize_app);
- String actionTitleDisableApp =
- context.getString(R.string.resource_overuse_notification_button_disable_app);
- String actionTitleUninstallApp =
- context.getString(R.string.resource_overuse_notification_button_uninstall_app);
+ String actionTitleCloseNotification =
+ context.getString(R.string.resource_overuse_notification_button_close_app);
for (int i = 0; i < packagesByImportance.size(); i++) {
int importance = packagesByImportance.keyAt(i);
@@ -250,46 +240,32 @@
for (int pkgIdx = 0; pkgIdx < packagesById.size(); pkgIdx++) {
int notificationId = packagesById.keyAt(pkgIdx);
String packageName = packagesById.valueAt(pkgIdx);
- String text = textUninstallApp;
- String negativeActionText = actionTitleUninstallApp;
CharSequence appName;
- PendingIntent positiveActionPendingIntent;
- PendingIntent negativeActionPendingIntent;
try {
ApplicationInfo info = packageManager.getApplicationInfoAsUser(packageName,
/* flags= */ 0, user);
appName = info.loadLabel(packageManager);
- negativeActionPendingIntent = positiveActionPendingIntent =
- getPendingIntent(context, CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, user,
- packageName, notificationId);
- // Apps with SYSTEM flag are considered bundled apps by car settings and
- // bundled apps have disable button rather than uninstall button.
- if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- text = textDisableApp;
- negativeActionText = actionTitleDisableApp;
- negativeActionPendingIntent = getPendingIntent(context,
- CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP, user, packageName,
- notificationId);
- }
} catch (PackageManager.NameNotFoundException e) {
Slogf.e(TAG, e, "Package '%s' not found for user %s", packageName, user);
continue;
}
- PendingIntent deletePendingIntent = getPendingIntent(context,
+ PendingIntent negativeActionPendingIntent = getPendingIntent(context,
CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION, user,
packageName, notificationId);
+ PendingIntent positiveActionPendingIntent = getPendingIntent(context,
+ CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, user, packageName, notificationId);
Notification notification = NotificationHelper
.newNotificationBuilder(context, importance)
.setSmallIcon(R.drawable.car_ic_warning)
.setContentTitle(TextUtils.expandTemplate(titleTemplate, appName))
- .setContentText(text)
+ .setContentText(textDisabledApp)
.setCategory(Notification.CATEGORY_CAR_WARNING)
.addAction(new Notification.Action.Builder(/* icon= */ null,
- actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+ actionTitleCloseNotification, negativeActionPendingIntent).build())
.addAction(new Notification.Action.Builder(/* icon= */ null,
- negativeActionText, negativeActionPendingIntent).build())
- .setDeleteIntent(deletePendingIntent)
+ actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+ .setDeleteIntent(negativeActionPendingIntent)
.build();
notificationManager.notifyAsUser(TAG, notificationId, notification, user);
@@ -300,8 +276,8 @@
+ "user %s.\nNotification { App name: %s, Importance: %d, "
+ "Description: %s, Positive button text: %s, Negative button "
+ "text: %s }",
- notificationId, user, appName, importance, text,
- actionTitlePrioritizeApp, negativeActionText);
+ notificationId, user, appName, importance, textDisabledApp,
+ actionTitleCloseNotification, actionTitlePrioritizeApp);
}
}
}
diff --git a/service/Android.bp b/service/Android.bp
index c84c874..23a82a3 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -195,6 +195,7 @@
filegroup {
name: "iscriptexecutor_aidl",
srcs: [
+ "src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl",
"src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl",
"src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutorListener.aidl",
],
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 1752eab..f763860 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -50,6 +50,14 @@
android:label="@string/car_permission_label_control_car_energy"
android:description="@string/car_permission_desc_control_car_energy"/>
+ <!-- Allows CarService to connect to OEM CarService.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.car.permission.BIND_OEM_CAR_SERVICE"
+ android:protectionLevel="signature|privileged"
+ android:label="@string/car_permission_label_bind_oem_car_service"
+ android:description="@string/car_permission_desc_bind_oem_car_service"/>
+
<!-- Allows an application to adjust the vehicle's range remaining information.
<p>Protection level: signature|privileged
-->
diff --git a/service/jni/evs/EvsServiceContext.cpp b/service/jni/evs/EvsServiceContext.cpp
index e3d7220..ff6f7ae 100644
--- a/service/jni/evs/EvsServiceContext.cpp
+++ b/service/jni/evs/EvsServiceContext.cpp
@@ -179,7 +179,8 @@
mCarEvsServiceObj = env->NewGlobalRef(thiz);
}
- // Reset a EvsDisplay handle
+ // Reset a stored camera id and a display handle
+ mCameraIdInUse.clear();
mDisplay = nullptr;
}
@@ -273,6 +274,10 @@
LOG(WARNING) << "Failed to close a current camera device.";
}
}
+
+ // Reset a camera reference and id in use.
+ mCamera.reset();
+ mCameraIdInUse.clear();
}
bool EvsServiceContext::startVideoStream() {
@@ -429,6 +434,7 @@
mService = nullptr;
mStreamHandler = nullptr;
mBufferRecords.clear();
+ mCameraIdInUse.clear();
}
LOG(ERROR) << "The native EVS service has died.";
diff --git a/service/jni/evs/EvsServiceContext.h b/service/jni/evs/EvsServiceContext.h
index 87966d1..38e1b5e 100644
--- a/service/jni/evs/EvsServiceContext.h
+++ b/service/jni/evs/EvsServiceContext.h
@@ -160,7 +160,7 @@
std::set<int> mBufferRecords GUARDED_BY(mLock);
// A name of the camera device currently in use.
- std::string_view mCameraIdInUse;
+ std::string mCameraIdInUse;
// List of available camera devices
std::vector<::aidl::android::hardware::automotive::evs::CameraDesc> mCameraList;
diff --git a/service/proto/android/car/telemetry/atoms.proto b/service/proto/android/car/telemetry/atoms.proto
index 4aad716..cd504f1 100644
--- a/service/proto/android/car/telemetry/atoms.proto
+++ b/service/proto/android/car/telemetry/atoms.proto
@@ -37,6 +37,7 @@
oneof pulled {
ProcessMemoryState process_memory_state = 10013;
ProcessCpuTime process_cpu_time = 10035;
+ ProcessMemorySnapshot process_memory_snapshot = 10064;
}
}
@@ -167,6 +168,19 @@
optional ErrorSource error_source = 5;
}
+message ProcessMemorySnapshot {
+ optional int32 uid = 1;
+ optional string process_name = 2;
+ optional int32 pid = 3;
+ optional int32 oom_score_adj = 4;
+ optional int32 rss_in_kilobytes = 5;
+ optional int32 anon_rss_in_kilobytes = 6;
+ optional int32 swap_in_kilobytes = 7;
+ optional int32 anon_rss_and_swap_in_kilobytes = 8;
+ optional int32 gpu_memory_kb = 9;
+ optional bool has_foreground_services = 10;
+}
+
message CarPowerStateChanged {
enum State {
WAIT_FOR_VHAL = 0;
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index 5bd0506..f2fe643 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Lewer template."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"beheer die oopmaak van programme"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Beheer die oopmaak van programme."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"bestuur draadprioriteit"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Bestuur draadprioriteit."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus het misluk"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageer nie. Ontprop hoofeenheidkas, prop dit weer in, en herbegin die motor"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Toestel"</string>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index 39ad921..e7c95ca 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"የቅንብር ደንቦችን ምስል ሥራ።"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"መተግበሪያዎችን ማስጀመር መቆጣጠር"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"መተግበሪያዎችን ማስጀመር መቆጣጠር።"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"የተከታታይ ቅድሚያን ያስተዳድሩ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"የተከታታይ ቅድሚያን ያስተዳድሩ።"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN አውቶብስ አልተሳካም"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN አውቶብስ ምላሽ አይሰጥም። የጭንቅላት አሃድ መያዣ ሳጥኑን ይሰኩ እና ይንቀሉ በመቀጠል መኪናውን ዳግም ያስጀምሩ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"የእኔ መሣሪያ"</string>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index b742435..a1a5c22 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -62,11 +62,11 @@
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"الانتباه إلى تغييرات حالة التنقل على شاشة مجموعة العدادات"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"ضبط قيود تجربة المستخدم"</string>
<string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"ضبط قيود تجربة المُستخدِم"</string>
- <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"الإذن بالاطّلاع على معرّف الشاشة الخاص"</string>
+ <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"إذن الوصول لقراءة معرّف الشاشة الخاص"</string>
<string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"يتيح إذن الوصول هذا قراءة معرّف الشاشة الخاص."</string>
<string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"التواصل مع جهاز USB في وضع AOAP"</string>
<string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"يتيح للتطبيق التواصل مع جهاز في وضع AOAP."</string>
- <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الإذن بالاطّلاع على Occupant Awareness System"</string>
+ <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"الوصول لقراءة Occupant Awareness System"</string>
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"السماح بقراءة حالة Occupant Awareness System وبيانات التعرف عليه"</string>
<string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"التحكّم في الرسم البياني لنظام Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"السماح بالتحكّم في بدء وإيقاف الرسم البياني للتعرف على Occupant Awareness System"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"عرض النماذج"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"التحكم في تشغيل التطبيقات"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"التحكم في تشغيل التطبيقات"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"إدارة أولوية سلسلة المحادثات"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"يمكنك إدارة أولوية سلسلة المحادثات."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"حدث خطأ في موصّل CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"لا استجابة من موصّل CAN. يمكنك فصل صندوق وحدة الرأس وإعادة تشغيل السيارة."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"جهازي"</string>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index b8b0f47..f567a47 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেমপ্লে’ট প্ৰদান কৰক।"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"এপ্লিকেশ্বন লঞ্চ হোৱাটো নিয়ন্ত্ৰণ কৰে।"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্ৰেডৰ অগ্ৰাধিকাৰ পৰিচালনা কৰক।"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাছ বিফল হৈছে"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাছে সঁহাৰি দিয়া নাই। হে’ড ইউনিট বাকচটো আঁতৰাই পুনৰ লগাওক"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"মোৰ ডিভাইচ"</string>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 0252fab..f872fb3 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları vizualizasiya edin."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"tətbiqlərin başladılmasına nəzarət"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Tətbiqlərin başladılmasına nəzarət."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mövzu prioritetini idarə edin"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mövzu prioritetini idarə edin."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN idarəetmə mexanizmi uğursuz oldu"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN mexanizmi cavab vermir. Əsas cihaz panelini ayırın və yenidən qoşun, sonra avtomobili yenidən işə salın"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index d4b970c..b2969e9 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Prikazivanje šablona."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola pokretanja aplikacija"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroliše pokretanje aplikacija."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN magistrale"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN magistrala ne reaguje. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index c964195..2e6f2ad 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Візуалізацыя шаблонаў."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"кіраванне запускам праграм"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Кіраванне запускам праграм."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"кіраваць прыярытэтам патокаў"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Кіраваць прыярытэтам патокаў."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-шына парушана"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шына не адказвае. Перападключыце канектар, а затым выключыце запальванне і паўторна завядзіце аўтамабіль"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мая прылада"</string>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index 5726b7c..15031e5 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендериране на шаблони."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление на приложенията, които се стартират"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление на приложенията, които се стартират."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление на приоритета на нишката"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление на приоритета на нишката."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка в CAN шината"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шината не реагира. Изключете и включете отново захранването на основното устройство и рестартирайте автомобила"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Моето устройство"</string>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index bd477db..6b3413c 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"টেম্পলেট রেন্ডার করুন।"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"অ্যাপ্লিকেশন চালু করা প্রক্রিয়া নিয়ন্ত্রণ করুন।"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"থ্রেডের অগ্রাধিকার ম্যানেজ করুন।"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN বাস কাজ করছে না"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN বাস কাজ করছে না। হেডইউনিট বক্স খুলে নিয়ে আবার লাগান ও গাড়ি রিস্টার্ট করুন"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"আমার ডিভাইস"</string>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index b9bf4cf..ef200fb 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Iscrtavanje šablona."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljanje pokretanjem aplikacija"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljanje pokretanjem aplikacija."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Greška CAN busa"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne reagira. Isključite i ponovo uključite glavnu jedinicu i ponovo pokrenite automobil"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 6ed24e3..535dc5d 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderitzar plantilles."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla l\'inici de les aplicacions"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla l\'inici de les aplicacions."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestiona la prioritat de les converses"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestiona la prioritat de les converses."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Ha fallat el bus CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no respon. Desendolla i torna a endollar el capçal i torna a engegar el cotxe."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"El meu dispositiu"</string>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 42c5f7a..5bb1d08 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykreslování šablon."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládání spouštěných aplikací"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládání spouštěných aplikací."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Sběrnice CAN selhala"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Sběrnice CAN neodpovídá. Odpojte a opět zapojte autorádio a znovu nastartujte auto"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje zařízení"</string>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index edd9fb0..3752122 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gengive skabeloner."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styre startapps"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styre startapps."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus (Controller Area Network) mislykkedes"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus (Controller Area Network) svarer ikke. Afbryd forbindelsen til bilens hovedenhed, tilslut den igen, og genstart bilen"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Min enhed"</string>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index ec03139..0f0d4d7 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeuginformationen"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"Fahrzeuginformationen"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"Zugriff auf Informationen deines Autos"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"auf die Autokamera zuzugreifen"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Auf Autokamera(s) zugreifen."</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vorlagen werden gerendert."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Der Start von Anwendungen wird gesteuert"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Der Start von Anwendungen wird gesteuert."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"Thread-Priorität verwalten"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-Priorität verwalten."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-Bus ausgefallen"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-Bus reagiert nicht. Trenne die Haupteinheit vom Stromnetz, schließe sie wieder an und starte das Auto."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mein Gerät"</string>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index 617fe62..84f8a50 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Να αποδίδει πρότυπα."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"έλεγχος εφαρμογών εκκίνησης"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Έλεγχος εφαρμογών εκκίνησης."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"διαχείριση προτεραιότητας νημάτων"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Διαχείριση προτεραιότητας νημάτων."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Αποτυχία διαύλου CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ο δίαυλος CAN δεν αποκρίνεται. Αποσυνδέστε και συνδέστε ξανά το πλαίσιο μονάδας κεφαλής και έπειτα επανεκκινήστε το αυτοκίνητο"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Η συσκευή μου"</string>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index 39fa611..ef982fb 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -27,7 +27,7 @@
<string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"adjust car’s range remaining"</string>
<string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Adjust car’s range remaining value."</string>
<string name="car_permission_label_hvac" msgid="1499454192558727843">"access car’s hvac"</string>
- <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s hvac."</string>
+ <string name="car_permission_desc_hvac" msgid="3754229695589774195">"Access your car’s HVAC."</string>
<string name="car_permission_label_mileage" msgid="4661317074631150551">"access car’s mileage information"</string>
<string name="car_permission_desc_mileage" msgid="7179735693278681090">"Access your car’s mileage information."</string>
<string name="car_permission_label_speed" msgid="1149027717860529745">"read car’s speed"</string>
@@ -52,7 +52,7 @@
<string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Control your car’s audio settings."</string>
<string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Application blocking"</string>
<string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Control application blocking while driving."</string>
- <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation Manager"</string>
+ <string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Navigation manager"</string>
<string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Report navigation data to instrument cluster"</string>
<string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Direct rendering to instrument cluster"</string>
<string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Allow an application to declare activities to be displayed in the instrument cluster"</string>
@@ -60,16 +60,16 @@
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Launch apps in the instrument cluster"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Instrument cluster navigation state"</string>
<string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Listen for instrument cluster navigation state changes"</string>
- <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX Restrictions Configuration"</string>
- <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX Restrictions"</string>
- <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display id"</string>
- <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display id"</string>
+ <string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"UX restrictions configuration"</string>
+ <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configure UX restrictions"</string>
+ <string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Read access to private display ID"</string>
+ <string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Allows read access to private display ID"</string>
<string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Communicate with USB device in AOAP mode"</string>
<string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Allows an app to communicate with a device in AOAP mode"</string>
- <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant Awareness System Read Access"</string>
- <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for Occupant Awareness System"</string>
- <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control Occupant Awareness System Graph"</string>
- <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stopping of the Occupant Awareness System detection graph"</string>
+ <string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Occupant awareness system read access"</string>
+ <string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Allows reading status and detection data for occupant awareness system"</string>
+ <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Control occupant awareness system graph"</string>
+ <string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Allows controlling the start and stop of the occupant awareness system detection graph"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"read diagnostic data"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Read diagnostic data from the car."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"clear diagnostic data"</string>
@@ -81,15 +81,15 @@
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"Flash storage monitoring"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitor flash storage usage"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"listen to driving state"</string>
- <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to Driving state changes."</string>
- <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use Car Telemetry Service"</string>
+ <string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</string>
+ <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Use car telemetry service"</string>
<string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Collect car system health data."</string>
- <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use Car EVS Service"</string>
+ <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Use car EVS service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscribe to EVS video streams"</string>
<string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Request the EVS preview activity"</string>
<string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Request the system to launch the EVS preview activity"</string>
<string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Control the EVS preview activity"</string>
- <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the sytsem"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Control the EVS preview activity of the system"</string>
<string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Use the EVS camera"</string>
<string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscribe to EVS camera streams"</string>
<string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitor the status of the EVS service"</string>
@@ -131,7 +131,7 @@
<string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"read car’s exterior temperature"</string>
<string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Access car’s exterior temperature."</string>
<string name="car_permission_label_car_tires" msgid="4379255261197836840">"access car’s tires information"</string>
- <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tire information."</string>
+ <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Access car’s tyre information."</string>
<string name="car_permission_label_car_steering" msgid="7779530447441232479">"read car’s steering angle information"</string>
<string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Access car’s steering angle information."</string>
<string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"read car display units"</string>
@@ -142,7 +142,7 @@
<string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Access car’s powertrain information."</string>
<string name="car_permission_label_car_power" msgid="8111448088314368268">"read car’s power state"</string>
<string name="car_permission_desc_car_power" msgid="9202079903668652864">"Access car’s power state."</string>
- <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enroll Trusted Device"</string>
+ <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Enrol Trusted Device"</string>
<string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Allow Trusted Device Enrollment"</string>
<string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Control car’s test mode"</string>
<string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Control car’s test mode"</string>
@@ -164,10 +164,8 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
- <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back headunit box and restart the car"</string>
+ <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
<string name="default_guest_name" msgid="2912812799433131476">"Guest"</string>
</resources>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index 3dff490..ef982fb 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back in head unit box and restart the car"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 1dd1a7d..7be1b4c 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Render templates."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"control launching applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Control launching applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"manage thread priority"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Manage thread priority."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus failed"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus does not respond. Unplug and plug back headunit box and restart the car"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"My Device"</string>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index 7092d40..234fc95 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla el inicio de las aplicaciones"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla el inicio de las aplicaciones."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrar prioridad de subprocesos"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administra la prioridad de subprocesos."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Error de bus CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus no responde. Desconecta y vuelve a conectar la caja de la unidad central y enciende nuevamente el auto"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index 2956a34..4f84835 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_permission_label" msgid="2215078736675564541">"Información sobre el coche"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"información sobre el coche"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"acceder a los datos de tu coche"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"acceder a la cámara del coche"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Acceder a las cámaras del coche."</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar plantillas."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla las aplicaciones abiertas"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla las aplicaciones abiertas."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionar la prioridad de las conversaciones"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionar la prioridad de las conversaciones."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Fallo de bus CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"El bus CAN no responde. Desconecta el cabezal, conéctalo de nuevo y reinicia el coche"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mi dispositivo"</string>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 0fc4de5..13e4a8c 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mallide renderdamine."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"rakenduste käivitamise juhtimine"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Rakenduste käivitamise juhtimine."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"saavad hallata ohu prioriteeti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Ohu prioriteedi haldamine."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-siin ebaõnnestus"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-siin ei reageeri. Eemaldage autoraadio üksus ja pange see tagasi ning taaskäivitage auto"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Minu seade"</string>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index 6f4c9b6..e1c2346 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -38,10 +38,10 @@
<string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Atzitu auto-saltzailearen kanala autoari buruzko informazio zehatza trukatzeko."</string>
<string name="car_permission_label_radio" msgid="6009465291685935112">"kudeatu autoaren irratia"</string>
<string name="car_permission_desc_radio" msgid="3385999027478186964">"Atzitu autoaren irratia."</string>
- <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoaren pantailan"</string>
- <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoaren pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
+ <string name="car_permission_label_projection" msgid="9107156380287576787">"proiektatu telefonoaren interfazea autoko pantailan"</string>
+ <string name="car_permission_desc_projection" msgid="2352178999656292944">"Telefonoaren interfazea autoko pantailan proiektatzeko baimena ematen dio aplikazioari."</string>
<string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"atzitu proiekzio-egoera"</string>
- <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoaren pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
+ <string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"Autoko pantailan proiektatutako aplikazioen egoera atzitzeko baimena ematen dio aplikazioari."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"kontrolatu autoaren audioaren bolumena"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"kudeatu autoaren audio-ezarpenak"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulatu autoaren hardware-abstrakzioaren geruza (HAL)"</string>
@@ -118,8 +118,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Atzitu autoaren saltzailearen baimenari buruzko informazioa"</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"irakurri autoaren kanpoaldeko argien egoera"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Atzitu autoaren kanpoaldeko argien egoera."</string>
- <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren erreferentziazko denbora tartearen ordua"</string>
- <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren erreferentziazko denbora tartearen ordua."</string>
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"atzitu autoaren epoch ordua"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Atzitu autoaren epoch ordua."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"atzitu autoaren enkriptazioa lotzeko hazia"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Atzitu autoaren enkriptazioa lotzeko hazia."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"irakurri autoaren kanpoaldeko argiak"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Errendatu txantiloiak."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolatu abiarazteko aplikazioak"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolatu abiarazteko aplikazioak."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"kudeatu elkarrizketa-harien lehentasuna"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Kudeatu elkarrizketa-harien lehentasuna."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN autobusak huts egin du"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus-ak ez du erantzuten. Desentxufatu eta entxufatu berriro gailu nagusia eta berrabiarazi autoa."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Nire gailua"</string>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index e3d3fb0..3ab9659 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"پرداز زدن الگوها."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"کنترل راهاندازی برنامهها"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"کنترل راهاندازی برنامهها."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"مدیریت اولویت رشته"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"مدیریت اولویت رشته."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"گذرگاه CAN ناموفق بود"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"گذرگاه CAN پاسخ نمیدهد. محفظه ضبطوپخش را جدا و سپس وصل کنید و خودرو را دوباره روشن کنید"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"دستگاه من"</string>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index f971a7d..6a12e4a 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderöi mallit."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"hallita sovellusten käynnistymistä"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"hallita sovellusten käynnistymistä."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hallitsee ketjujen priorisointia"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hallitsee ketjujen priorisointia."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-väylä hylättiin"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-väylä ei vastaa. Irrota pääyksikkö ja liitä se takaisin. Käynnistä auto sitten uudelleen."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Oma laite"</string>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index 32aeca5..3e65de2 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Effectuer un rendu des modèles."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité du fil d\'exécution"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité du fil d\'exécution."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Défaillance du bus de données CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité centrale, puis redémarrez la voiture"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index a29ef28..e2979c9 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Afficher les modèles."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"contrôler le lancement d\'applications."</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Contrôler le lancement d\'applications."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gérer la priorité des threads"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gérer la priorité des threads."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Échec du bus de données CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Le bus de données CAN ne répond pas. Débranchez et rebranchez le boîtier de l\'unité principale, puis redémarrez la voiture"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mon appareil"</string>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index 8ebfe66..25b2a3f 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -118,8 +118,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Acceder á información sobre os permisos do vendedor do coche."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ler o estado das luces exteriores do dispositivo"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Acceder ao estado das luces exteriores do coche."</string>
- <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao inicio do rexistro de tempo do coche"</string>
- <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao inicio do rexistro de tempo do coche."</string>
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"acceder ao tempo epoch do coche"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Acceder ao tempo epoch do coche."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"acceder á semente de vinculación de encriptación do coche"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Acceder á semente de vinculación de encriptación do coche."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ler as luces exteriores do coche"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Xerar modelos."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o inicio de aplicacións"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o inicio de aplicacións."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"xestionar prioridade das conversas"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Xestionar prioridade das conversas."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Produciuse un erro no bus CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O bus CAN non responde. Desconecta a caixa da unidade principal, conéctaa de novo e reinicia o coche"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 9aaaacd..a41b9fc 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"નમૂના જનરેટ કરો."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"લૉન્ચિંગ ઍપ્લિકેશનો નિયંત્રિત કરો."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"થ્રેડની પ્રાધાન્યતા મેનેજ કરો."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN બસ નિષ્ફળ રહી"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN બસ પ્રતિસાદ આપતી નથી. હેડયુનિટ બોક્સને અનપ્લગ કરી ફરી પ્લગ કરો અને કારને ફરી શરૂ કરો"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"મારું ડિવાઇસ"</string>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 5c38a70..e457d73 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेंप्लेट बनाएं."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लॉन्च किए जाने वाले ऐप्लिकेशन कंट्रोल करता है."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेड की प्राथमिकता मैनेज करने की अनुमति दें."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"\'CAN बस\' काम नहीं कर पा रहा है"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"\'CAN बस\' जवाब नहीं दे रहा है. हेडयूनिट बॉक्स का प्लग निकालकर वापस लगाएं और कार को रीस्टार्ट करें"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"मेरा डिवाइस"</string>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index 780dc07..77b4a88 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Generirati predloške."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"upravljajte pokretanjem aplikacija"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Upravljajte pokretanjem aplikacija."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prioritetom niti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prioritetom niti."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Pogreška CAN busa"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ne odgovara. Iskopčajte i ponovo ukopčajte glavnu jedinicu i ponovo pokrenite automobil"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moj uređaj"</string>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index e5e462b..3285cfc 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Sablonok renderelése."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"alkalmazásindítás vezérlése"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Alkalmazásindítás vezérlése."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"témaszál-prioritás kezelése"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Témaszál-prioritás kezelése."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"A CAN-busz hibát észlelt"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"A CAN-busz nem válaszol. Csatlakoztassa újra a fejegységet, és indítsa újra az autót."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Saját eszköz"</string>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index c93caf7..71839fd 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Ձևանմուշների արտապատկերում։"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"վերահսկել հավելվածների գործարկումը"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Վերահսկել հավելվածների գործարկումը"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"կառավարել Тhread-ի առաջնահերթությունը"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Կառավարել Тhread-ի առաջնահերթությունը։"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN անվադողի սխալ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN անվադողը չի պատասխանում: Անջատեք և նորից միացրեք միակցիչը, ապա անջատեք վառոցքը և վերագործարկեք մեքենան:"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Իմ սարքը"</string>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index 0ace097..f527b85 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Merender template."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengontrol aplikasi yang diluncurkan"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrol aplikasi yang diluncurkan."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mengelola prioritas thread"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mengelola prioritas thread."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus gagal"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus tidak merespons. Cabut dan colokkan kembali boks headunit, lalu nyalakan ulang mobil"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Perangkat Saya"</string>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 91116e4..4995bb8 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Teikna sniðmát."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"stjórna ræsingu forrita"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Stjórna ræsingu forrita."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"stjórna forgangi þráða"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Stjórna forgangi þráða."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Bilun í CAN-gagnabraut"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-gagnabraut svarar ekki. Taktu stjórneiningarboxið úr sambandi, settu það aftur í samband og gangsettu bílinn aftur."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Tækið mitt"</string>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index 113d4b7..958d15b 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Consente di visualizzare i modelli."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controllo avvio delle applicazioni"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controllo avvio delle applicazioni."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestione della priorità dei thread"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestione della priorità dei thread."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Comunicazione tramite bus CAN non riuscita"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Il bus CAN non risponde. Scollega e ricollega l\'unità principale e riaccendi il motore."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mio dispositivo"</string>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index e8ddd2a..84ba79a 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"עיבוד תבניות."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"שליטה בהפעלת אפליקציות"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"יש שליטה בהפעלת אפליקציות."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ניהול העדיפות של השרשורים"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ניהול העדיפות של השרשורים."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"פרוטוקול CAN bus נכשל"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"פרוטוקול CAN bus לא מגיב. יש לנתק ולחבר שוב את מערכת הסטריאו ולהתניע מחדש את הרכב"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"המכשיר שלי"</string>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index a741cfb..49cc734 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"テンプレートの表示。"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"起動アプリの管理"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"起動アプリの管理。"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"スレッドの優先度の管理"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"スレッドの優先度の管理"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN バスでエラーが発生しました"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN バスが応答しません。ヘッドユニット ボックスのプラグを抜いて接続し直し、車を再始動してください"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"自分のデバイス"</string>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index 96977f6..548f5dc 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"შაბლონების ჩვენება."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"აპლიკაციების გაშვების კონტროლი"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"აპლიკაციების გაშვების კონტროლი."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"თემატური გზავნილების პრიორიტეტულობის მართვა"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"თემატური გზავნილების პრიორიტეტულობის მართვა."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"წარმოიშვა CAN-სალტის შეცდომა"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-სალტე არ რეაგირებს. გამოაერთეთ და ხელახლა მიაერთეთ საინფორმაციო-გასართობი მოწყობილობა, შემდეგ კი ხელახლა დაქოქეთ მანქანა"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ჩემი მოწყობილობა"</string>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index 1be18a5..620c0c9 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Рендеринг үлгілері"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"қолданбалардың іске қосылуын басқару"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Қолданбалардың іске қосылуын басқара аласыз."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"тізбек басымдығын басқару"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Тізбек басымдығын басқарыңыз."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN шинасы істен шықты"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN шинасы жауап бермейді. Негізгі модульді ажыратып, қайта жалғаңыз және көлікті қайта оталдырыңыз"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Құрылғым"</string>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 12d2339..621b072 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"បំប្លែងទម្រង់គំរូ។"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"គ្រប់គ្រងការចាប់ផ្ដើមកម្មវិធី"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"គ្រប់គ្រងការចាប់ផ្ដើមកម្មវិធី។"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"គ្រប់គ្រងអាទិភាពកម្រងសារ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"គ្រប់គ្រងអាទិភាពកម្រងសារ"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"មិនអាចដំណើរការ CAN bus បានទេ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus មិនឆ្លើយតបទេ។ សូមផ្ដាច់ រួចភ្ជាប់ប្រអប់ឧបករណ៍ចាក់តន្ត្រីម្តងទៀត បន្ទាប់មកបញ្ឆេះរថយន្តឡើងវិញ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ឧបករណ៍របស់ខ្ញុំ"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index 9134516..3fec736 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -40,7 +40,7 @@
<string name="car_permission_desc_radio" msgid="3385999027478186964">"ಕಾರಿನ ರೇಡಿಯೋವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
<string name="car_permission_label_projection" msgid="9107156380287576787">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="car_permission_desc_projection" msgid="2352178999656292944">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿರುವ ಫೋನ್ನಿಂದ ಇಂಟರ್ ಫೇಸ್ ಅನ್ನು ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರೊಜೆಕ್ಷನ್ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+ <string name="car_permission_label_access_projection_status" msgid="4231618890836627402">"ಪ್ರಕ್ಷೇಪಣೆ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="car_permission_desc_access_projection_status" msgid="8497351979100616278">"ಕಾರಿನ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರಾಜೆಕ್ಟ್ ಮಾಡುವ ಇತರ ಆ್ಯಪ್ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪಡೆಯಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"ಕಾರಿನ ಆಡಿಯೋ ವಾಲ್ಯೂಮ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"ಕಾರಿನ ಆಡಿಯೋ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ಟೆಂಪ್ಲೇಟ್ಗಳನ್ನು ರೆಂಡರ್ ಮಾಡಿ."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ಪ್ರಾರಂಭಿಸುವ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ಥ್ರೆಡ್ ಆದ್ಯತೆಯನ್ನು ನಿರ್ವಹಿಸಿ."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"ಸಿಎಎನ್ ಬಸ್ ಕೆಟ್ಟಿದೆ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ಬಸ್ ಸ್ಪಂದಿಸುತ್ತಿಲ್ಲ. ಹೆಡ್ ಯುನಿಟ್ ಪೆಟ್ಟಿಗೆಯನ್ನು ಅನ್ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತೆ ಪ್ಲಗ್ ಮಾಡಿ ಕಾರನ್ನು ಪುನರಾರಂಭಿಸಿ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ನನ್ನ ಸಾಧನ"</string>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index 3d5a3a8..fd40bf9 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"템플릿 렌더링"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"애플리케이션 실행을 제어합니다."</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"애플리케이션 실행을 제어합니다."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"대화목록 우선순위 관리"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"대화목록 우선순위를 관리합니다."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 버스 실패"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 버스가 응답하지 않습니다. 헤드유닛 박스를 분리한 후 다시 연결한 다음 시동을 다시 걸어 보세요."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"내 기기"</string>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index d468a7f..8d808d9 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -20,8 +20,8 @@
<string name="car_permission_desc" msgid="3584369074931334964">"унааңыз тууралуу маалымат алынат"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"унаадагы камерага мүмкүнчүлүк алуу"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Унааңыздын камераларын колдонуу."</string>
- <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалымат алуу"</string>
- <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалымат алуу."</string>
+ <string name="car_permission_label_energy" msgid="7409144323527821558">"унаанын кубаты тууралуу маалыматты көрүү"</string>
+ <string name="car_permission_desc_energy" msgid="3392963810053235407">"Унааңыздын кубаты тууралуу маалыматты көрүү."</string>
<string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөө"</string>
<string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"Электромобилди кубаттоо жөндөөлөрүн көзөмөлдөңүз."</string>
<string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"унаа дагы канча аралыкты басып өтөрүн тууралоо"</string>
@@ -131,7 +131,7 @@
<string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"унаанын сыртындагы температураны окуу"</string>
<string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Унаанын сыртындагы температураны көрүү."</string>
<string name="car_permission_label_car_tires" msgid="4379255261197836840">"унаа дөңгөлөктөрү тууралуу маалыматты окуу"</string>
- <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалымат алуу."</string>
+ <string name="car_permission_desc_car_tires" msgid="8134496466769810134">"Унаанын дөңгөлөктөрү тууралуу маалыматты көрүү."</string>
<string name="car_permission_label_car_steering" msgid="7779530447441232479">"унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү"</string>
<string name="car_permission_desc_car_steering" msgid="1357331844530708138">"Унаанын рулун буруу бурчуна тиешелүү маалыматты көрүү."</string>
<string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"унаанын дисплей бөлүмдөрүн окуу"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Үлгүлөрдү түзүү."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"иштетилген колдонмолорду көзөмөлдөө"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Иштетилген колдонмолорду көзөмөлдөңүз."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"маектин маанилүүлүгүн башкаруу"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Маектин маанилүүлүгүн башкаруу."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN иштебей калды"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN жооп бербей жатат. Башкы шайман блогун сууруп, кайра сайгандан кийин унааны кайра жүргүзүңүз"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Түзмөгүм"</string>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index 26aa899..d07bf73 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ສະແດງແມ່ແບບ."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ຄວບຄຸມການເປີດໃຊ້ແອັບພລິເຄຊັນ."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ຈັດການຄວາມສຳຄັນຂອງຫົວຂໍ້."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus ບໍ່ສຳເລັດ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ບໍ່ຕອບສະໜອງ. ຖອດປລັກກ່ອງເຄື່ອງຫຼິ້ນວິທະຍຸ (Headunit) ແລ້ວສຽບເຂົ້າຄືນໃໝ່ ແລະ ຣິສະຕາດລົດ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ອຸປະກອນຂອງຂ້ອຍ"</string>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 6d9f0df..38ebbc1 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Pateikti šablonus."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"Valdyti paleidžiamas programas"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Valdyti paleidžiamas programas."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"tvarkyti instrukcijų sekos prioritetą"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Tvarkyti instrukcijų sekos prioritetą."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN BUS klaida"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN BUS nereaguoja. Atjunkite ir vėl prijunkite pagrindinio įtaiso dėžutę."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mano įrenginys"</string>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index adb0907..c3a2a13 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Atveidot veidnes."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lietojumprogrammu palaišanas kontrole"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lietojumprogrammu palaišanas kontrole."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pārvaldīt pavediena prioritāti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pārvaldīt pavediena prioritāti."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Radās atteice datu maģistrālē"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Datu maģistrāle nereaģē. Atvienojiet un atkal pievienojiet stereosistēmas paneļa kabeli un atkārtoti iedarbiniet automašīnu"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mana ierīce"</string>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index 5936bf5..42b0c73 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="car_permission_label" msgid="2215078736675564541">"податоци за автомобилот"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"може да пристапуваат до податоците за автомобилот"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"пристапува до податоците за автомобилот"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"пристапува до камерата на автомобилот"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Пристапува до камерите на автомобилот."</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"пристапува до информациите за енергијата на автомобилот"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Прикажување шаблони."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"да го контролира стартувањето апликации"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"да го контролира стартувањето апликации"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"да управуваат со приоритетот на thread"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"да управуваат со приоритетот на thread"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-магистралата не успеа"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-магистралата не реагира. Откачете ја и повторно прикачете ја кутијата на главната единица и рестартирајте го автомобилот"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мојот уред"</string>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 2061442..8487ac5 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ടെംപ്ലേറ്റുകൾ റെൻഡർ ചെയ്യുക."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ലോഞ്ച് ചെയ്യുന്ന ആപ്പുകൾ നിയന്ത്രിക്കാം."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ത്രെഡ് മുൻഗണന മാനേജ് ചെയ്യുക."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ബസ് പരാജയപ്പെട്ടു"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ബസ് പ്രതികരിക്കുന്നില്ല. ഹെഡ്യൂണിറ്റ് ബോക്സ്, അൺപ്ലഗ് ചെയ്ത്, വീണ്ടും പ്ലഗ് ചെയ്ത്, കാർ റീസ്റ്റാർട്ട് ചെയ്യുക"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"എന്റെ ഉപകരണം"</string>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index b720a70..57faca2 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Загварыг буулгана."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"аппликэйшн эхлүүлэхийг хянаарай"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Аппликэйшн эхлүүлэхийг хянаарай."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"хуулбар процессыг чухалчлахыг удирдах"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Хуулбар процессыг чухалчлахыг удирдах."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus амжилтгүй болсон"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus хариу өгөхгүй байна. Хөгжим тоглуулагчийн хайрцгийг салгаад, дахин залгаж, машиныг дахин эхлүүлнэ үү"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Миний төхөөрөмж"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 4fdc968..8432a4f 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्पलेट रेंडर करा."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"लाँच होत असलेली अॅप्लिकेशन नियंत्रित करा"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"लाँच होत असलेली अॅप्लिकेशन नियंत्रित करा."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडशी संबंधित प्राधान्य व्यवस्थापित करा."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN बस अयशस्वी"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN बस प्रतिसाद देत नाही. हेडयुनिट बॉक्स अनप्लग करून पुन्हा प्लग करा आणि कार रीस्टार्ट करा"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"माझे डिव्हाइस"</string>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 28f1e31..79fd058 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Paparkan templat."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"mengawal pelancaran aplikasi"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Mengawal pelancaran aplikasi."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"urus keutamaan urutan"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Urus keutamaan urutan."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Bas CAN gagal"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Bas CAN tidak bertindak balas. Cabut dan palamkan kembali kotak unit stereo dan mulakan semula kereta"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Peranti Saya"</string>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index 49e37f6..478227a 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="car_permission_label" msgid="2215078736675564541">"ကားအချက်အလက်"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုနိုင်သည်"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"သင့်ကား၏ အချက်အလက်များကို အသုံးပြုပါမည်"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"ကား၏ ကင်မရာကို အသုံးပြုပါမည်"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"သင့်ကား၏ ကင်မရာ(များ)ကို ဝင်ရောက်အသုံးပြုပါမည်။"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"ကား၏ စွမ်းအင်အချက်အလက်များကို ရယူပါမည်"</string>
@@ -142,8 +142,8 @@
<string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"အင်ဂျင်အားဖြင့် ကားဝင်ရိုးလည်ပတ်မှုအချက်အလက်များကို ရယူပါမည်"</string>
<string name="car_permission_label_car_power" msgid="8111448088314368268">"ကား၏ ပါဝါအခြေအနေကို ကြည့်ပါမည်"</string>
<string name="car_permission_desc_car_power" msgid="9202079903668652864">"ကား၏ ပါဝါအခြေအနေကို ရယူပါမည်။"</string>
- <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"စိတ်ချရသည့်စက်ပစ္စည်းကို စာရင်းသွင်းရန်"</string>
- <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"စိတ်ချရသည့်စက်ပစ္စည်း စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
+ <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"ယုံကြည်ရသည့် ကိရိယာကို စာရင်းသွင်းရန်"</string>
+ <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"ယုံကြည်ရသည့် ကိရိယာအား စာရင်းသွင်းခြင်းကို ခွင့်ပြုရန်"</string>
<string name="car_permission_label_car_test_service" msgid="9159328930558208708">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
<string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"ကား၏ စမ်းသပ်မုဒ်ကို ထိန်းချုပ်ရန်"</string>
<string name="car_permission_label_control_car_features" msgid="3905791560378888286">"ကား၏ ဝန်ဆောင်မှုများကို ပိတ်ရန် သို့မဟုတ် ပိတ်ရန်"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"နမူနာပုံစံများ ပုံဖော်မည်။"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ဖွင့်ထားသည့် အပလီကေးရှင်းများကို ထိန်းချုပ်ခြင်း။"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ဦးစားပေး Thread စီမံရန်"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ဦးစားပေး Thread စီမံနိုင်သည်။"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"\"CAN bus\" စနစ် အသုံးပြုမှု မအောင်မြင်ပါ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus စနစ်က တုန့်ပြန်မှုမရှိပါ။ စက်အထိုင်ဘောက်စ်ကို ပလတ်ဖြုတ်ပြီး ပြန်တပ်ကာ ကားကို ပြန်လည်စတင်ပါ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ကျွန်ုပ်၏စက်"</string>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index b2d85c2..c7057c3 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -68,7 +68,7 @@
<string name="car_permission_desc_car_handle_usb_aoap_device" msgid="273505990971317034">"Tillater at en app kommuniserer med en enhet i AOAP-modus"</string>
<string name="car_permission_label_read_car_occupant_awareness_state" msgid="125517953575032758">"Lesetilgang til Occupant Awareness System"</string>
<string name="car_permission_desc_read_car_occupant_awareness_state" msgid="188865882598414986">"Lar deg lese av status og registreringsdata for Occupant Awareness System"</string>
- <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontroller diagrammet for Occupant Awareness System"</string>
+ <string name="car_permission_label_control_car_occupant_awareness_system" msgid="7163330266691094542">"Kontrollér diagrammet for Occupant Awareness System"</string>
<string name="car_permission_desc_control_car_occupant_awareness_system" msgid="7123482622084531911">"Lar deg kontrollere start og stopp av registreringsdiagrammet for Occupant Awareness System"</string>
<string name="car_permission_label_diag_read" msgid="7248894224877702604">"lese diagnostikkdata"</string>
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"Les diagnostikkdata fra bilen."</string>
@@ -99,17 +99,17 @@
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få tilgang til tanklokket og ladeporten på bilen"</string>
<string name="car_permission_desc_car_energy_ports" msgid="7771185999828794949">"Tilgang til tanklokket og ladeporten på bilen."</string>
<string name="car_permission_label_control_car_energy_ports" msgid="4375137311026313475">"kontrollere tanklokket og ladeporten på bilen"</string>
- <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontroller tanklokket og ladeporten på bilen."</string>
+ <string name="car_permission_desc_control_car_energy_ports" msgid="7364633710492525387">"Kontrollér tanklokket og ladeporten på bilen."</string>
<string name="car_permission_label_car_identification" msgid="5896712510164020478">"lese bilens identifikator"</string>
<string name="car_permission_desc_car_identification" msgid="4132040867171275059">"Tilgang til bilens identifikasjon."</string>
<string name="car_permission_label_control_car_doors" msgid="3032058819250195700">"kontrollére bildørene"</string>
- <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontroller bildørene."</string>
+ <string name="car_permission_desc_control_car_doors" msgid="6287353311980590092">"Kontrollér bildørene."</string>
<string name="car_permission_label_control_car_windows" msgid="2452854429996653029">"kontrollére bilvinduene"</string>
- <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontroller bilvinduene."</string>
+ <string name="car_permission_desc_control_car_windows" msgid="7693657991521595635">"Kontrollér bilvinduene."</string>
<string name="car_permission_label_control_car_mirrors" msgid="8470700538827409476">"kontrollére bilspeilene"</string>
- <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontroller bilspeilene."</string>
+ <string name="car_permission_desc_control_car_mirrors" msgid="1224135684068855032">"Kontrollér bilspeilene."</string>
<string name="car_permission_label_control_car_seats" msgid="1826934820585497135">"kontrollére bilsetene"</string>
- <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontroller bilsetene."</string>
+ <string name="car_permission_desc_control_car_seats" msgid="2407536601226470563">"Kontrollér bilsetene."</string>
<string name="car_permission_label_car_info" msgid="4707513570676492315">"få tilgang til grunnleggende informasjon om bilen"</string>
<string name="car_permission_desc_car_info" msgid="2118081474543537653">"Tilgang til grunnleggende informasjon om bilen."</string>
<string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"få tilgang til bilens konfidensielle informasjon"</string>
@@ -123,11 +123,11 @@
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ha tilgang til bilens bindingskilde for kryptering"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ha tilgang til bilens bindingskilde for kryptering"</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"lese bilens utvendige lys"</string>
- <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontroller bilens utvendige lys."</string>
+ <string name="car_permission_desc_control_car_exterior_lights" msgid="6332252612685264180">"Kontrollér bilens utvendige lys."</string>
<string name="car_permission_label_car_interior_lights" msgid="8506302199784427680">"lese bilens innvendige lys"</string>
<string name="car_permission_desc_car_interior_lights" msgid="6204775354692372506">"Tilgang til tilstanden til bilens innvendige lys."</string>
<string name="car_permission_label_control_car_interior_lights" msgid="6685386372012664281">"kontrollére bilens utvendige lys"</string>
- <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontroller bilens utvendige lys."</string>
+ <string name="car_permission_desc_control_car_interior_lights" msgid="797201814109701538">"Kontrollér bilens utvendige lys."</string>
<string name="car_permission_label_car_exterior_environment" msgid="3385924985991299436">"lese temperaturen utenfor bilen"</string>
<string name="car_permission_desc_car_exterior_environment" msgid="1716656004731603379">"Tilgang til temperaturen utenfor bilen."</string>
<string name="car_permission_label_car_tires" msgid="4379255261197836840">"få informasjon om bildekkene"</string>
@@ -137,35 +137,33 @@
<string name="car_permission_label_read_car_display_units" msgid="7617008314862097183">"lese bilens visningsenheter"</string>
<string name="car_permission_desc_read_car_display_units" msgid="6891898275208542385">"Les visningsenheter."</string>
<string name="car_permission_label_control_car_display_units" msgid="4975303668183173076">"kontrollére bilens visningsenheter"</string>
- <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontroller visningsenheter."</string>
+ <string name="car_permission_desc_control_car_display_units" msgid="8744397195158556945">"Kontrollér visningsenheter."</string>
<string name="car_permission_label_car_powertrain" msgid="4586122326622134886">"lese informasjon om bilens drivlinje"</string>
<string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Tilgang til informasjon om bilens drivlinje."</string>
<string name="car_permission_label_car_power" msgid="8111448088314368268">"lese bilens batterinivå"</string>
<string name="car_permission_desc_car_power" msgid="9202079903668652864">"Tilgang til bilens batterinivå."</string>
<string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Registrer en godkjent enhet"</string>
<string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Tillat registrering av godkjente enheter"</string>
- <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontroller bilens testmodus"</string>
- <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontroller bilens testmodus"</string>
+ <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Kontrollér bilens testmodus"</string>
+ <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Kontrollér bilens testmodus"</string>
<string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Slå bilens funksjoner på eller av"</string>
<string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Slå bilens funksjoner på eller av."</string>
<string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"bruk vakthund for bil"</string>
<string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Bruk vakthund for bil."</string>
- <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontroller konfigurasjonen for bilens vakthund"</string>
- <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontroller konfigurasjonen for bilens vakthund."</string>
+ <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"kontrollér konfigurasjonen for bilens vakthund"</string>
+ <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Kontrollér konfigurasjonen for bilens vakthund."</string>
<string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"samle inn beregninger om bilens vakthund"</string>
<string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Samle inn beregninger om bilens vakthund."</string>
<string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"les bilens regler for av/på"</string>
<string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Les bilens regler for av/på."</string>
- <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontroller bilens regler for av/på"</string>
- <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontroller bilens regler for av/på."</string>
+ <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"kontrollér bilens regler for av/på"</string>
+ <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Kontrollér bilens regler for av/på."</string>
<string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"justere nedstengingsprosessen"</string>
<string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"justere nedstengingsprosessen"</string>
<string name="car_permission_label_template_renderer" msgid="3464887382919754850">"gjengi maler"</string>
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Gjengi maler."</string>
- <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontroller åpning av apper"</string>
- <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontroller åpning av apper."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"administrer trådprioritet"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Administrer trådprioritet"</string>
+ <string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollér åpning av apper"</string>
+ <string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollér åpning av apper."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus mislyktes"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus svarer ikke. Koble bilens hovedenhet ut og inn igjen, og start bilen på nytt"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Enheten min"</string>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index 1c93755..9746593 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"टेम्प्लेटहरू रेन्डर गर्ने।"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"एपहरू लन्च गर्ने कुरा नियन्त्रण गर्नुहोस्।"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"थ्रेडको प्राथमिकता व्यवस्थापन गर्ने।"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus असफल भयो"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus ले प्रतिक्रिया जनाएन। हेडयुनिट बाकसलाई प्लगबाट निकालेर फेरि प्लगमा घुसाउनुहोस् र कार पुनःसुरु गर्नुहोस्"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"मेरो डिभाइस"</string>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index ee0de95..995ba18 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Templates renderen."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"starten van apps beheren"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Starten van apps beheren."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"thread-prioriteit beheren"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Thread-prioriteit beheren."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN-bus is mislukt"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bus reageert niet. Koppel de hoofdeenheid los en sluit deze vervolgens weer aan. Start de auto daarna opnieuw."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Mijn apparaat"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 0686fba..69d50e2 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="car_permission_label" msgid="2215078736675564541">"କାର୍ର ସୂଚନା"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ କରନ୍ତୁ"</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"ଆପଣଙ୍କ କାରର ସୂଚନା ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"କାର୍\'ର କ୍ୟାମେରାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"ଆପଣଙ୍କ କାର୍ର କ୍ୟାମେରା(ଗୁଡ଼ିକ) ଆକ୍ସେସ୍ କରିପାରେ।"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"କାର୍\'ର ଏନାର୍ଜି ସୂଚନାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ଟେମ୍ପଲେଟ୍ ରେଣ୍ଡର୍ କରନ୍ତୁ।"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ଆପ୍ଲିକେସନଗୁଡ଼ିକର ଲଞ୍ଚିଂକୁ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ଥ୍ରେଡ ପ୍ରାଥମିକତାକୁ ପରିଚାଳନା କରନ୍ତୁ।"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ବସ୍ ବିଫଳ ହେଲା"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ବସ୍ ପ୍ରତିକ୍ରିୟା ଦେଉନାହିଁ। ହେଡୟୁନିଟ୍ ବାକ୍ସର ପ୍ଲଗ୍ କାଢ଼ି ପୁଣି ଲଗାନ୍ତୁ ଏବଂ କାର୍କୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ମୋ ଡିଭାଇସ୍"</string>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index 1195ea4..6c45f8d 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -76,8 +76,8 @@
<string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"ਕਾਰ ਦਾ ਤਸ਼ਖੀਸੀ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ।"</string>
<string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ਪ੍ਰਕਾਸ਼ਕ"</string>
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS ਸੁਨੇਹੇ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ"</string>
- <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਸਬਸਕ੍ਰਾਈਬਰ"</string>
- <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+ <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS ਗਾਹਕ"</string>
+ <string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS ਸੁਨੇਹਿਆਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਦਾ ਨਿਰੀਖਣ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ਫਲੈਸ਼ ਸਟੋਰੇਜ ਵਰਤੋਂ ਦਾ ਨਿਰੀਖਣ"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"ਗੱਡੀ ਚਲਾਉਣ ਦੀ ਸਥਿਤੀ ਨੂੰ ਜਾਣਨਾ"</string>
@@ -85,13 +85,13 @@
<string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"ਕਾਰ ਟੈਲੀਮੀਟਰੀ ਸੇਵਾ ਵਰਤੋ"</string>
<string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"ਕਾਰ ਸਿਸਟਮ ਸਿਹਤ ਡਾਟਾ ਇਕੱਤਰ ਕਰੋ।"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"ਕਾਰ ਦੀ EVS ਸੇਵਾ ਵਰਤੋ"</string>
- <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+ <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS ਵੀਡੀਓ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਲਈ ਬੇਨਤੀ ਕਰੋ"</string>
<string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਲਾਂਚ ਕਰਨ ਲਈ ਸਿਸਟਮ ਨੂੰ ਬੇਨਤੀ ਕਰੋ"</string>
<string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"ਸਿਸਟਮ ਦੀ EVS ਪੂਰਵ-ਝਲਕ ਸਰਗਰਮੀ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS ਕੈਮਰਾ ਵਰਤੋ"</string>
- <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਬਸਕ੍ਰਾਈਬ ਕਰੋ"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS ਕੈਮਰਾ ਸਟ੍ਰੀਮਾਂ ਦੇ ਗਾਹਕ ਬਣੋ"</string>
<string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ"</string>
<string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS ਸੇਵਾ ਦੀ ਸਥਿਤੀ ਸੰਬੰਧੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਣੋ"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਪੂਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"ਟੈਮਪਲੇਟਾਂ ਨੂੰ ਰੈਂਡਰ ਕਰੋ।"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ਲਾਂਚ ਕੀਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ।"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"ਥ੍ਰੈੱਡ ਸੰਬੰਧੀ ਤਰਜੀਹ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN ਬੱਸ ਅਸਫਲ ਰਹੀ"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN ਬੱਸ ਕੰਮ ਨਹੀਂ ਕਰਦੀ। ਹੈੱਡ ਯੂਨਿਟ ਬਾਕਸ ਨੂੰ ਅਨਪਲੱਗ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਪਲੱਗ ਲਗਾ ਕੇ ਕਾਰ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"ਮੇਰਾ ਡੀਵਾਈਸ"</string>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index b441fab..30b0180 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderowanie szablonów."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrola nad uruchamianiem aplikacji"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrola nad uruchamianiem aplikacji."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"zarządzanie priorytetem wątków"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Zarządzanie priorytetem wątków."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Błąd magistrali CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nie odpowiada. Odłącz i jeszcze raz podłącz moduł główny i ponownie uruchom samochód."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje urządzenie"</string>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index f48e174..76b5daf 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controlar o início de aplicações"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlar o início de aplicações."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerir prioridade das discussões"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Faça a gestão da prioridade das discussões."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no CAN bus."</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O CAN bus não responde. Desligue e volte a ligar a caixa da unidade principal e reinicie o automóvel."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispositivo"</string>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index fbb6c98..d3d6871 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Renderizar modelos."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"controla a inicialização de aplicativos"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controla a inicialização de aplicativos."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gerenciar prioridade da conversa"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gerenciar prioridade da conversa."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Falha no barramento CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"O barramento CAN parou de responder. Desconecte e conecte novamente a caixa da unidade principal, depois ligue o carro"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Meu dispositivo"</string>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index d498f40..89a34e6 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_permission_label" msgid="2215078736675564541">"informațiile despre mașină"</string>
+ <string name="car_permission_label" msgid="2215078736675564541">"Accesează informațiile despre mașină"</string>
<string name="car_permission_desc" msgid="3584369074931334964">"să acceseze informațiile despre mașină"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"Accesează camera mașinii"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Accesează camerele mașinii."</string>
@@ -24,8 +24,8 @@
<string name="car_permission_desc_energy" msgid="3392963810053235407">"Accesează informațiile despre energie ale mașinii."</string>
<string name="car_permission_label_control_car_energy" msgid="2788215385574313796">"să gestioneze setările pentru încărcarea mașinii electrice"</string>
<string name="car_permission_desc_control_car_energy" msgid="8765015897869031807">"să gestioneze setările pentru încărcarea mașinii electrice."</string>
- <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustează restul distanței parcurse de mașină"</string>
- <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustează restul distanței parcurse de mașină."</string>
+ <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"ajustați restul distanței parcurse de mașină"</string>
+ <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Ajustați restul distanței parcurse de mașină."</string>
<string name="car_permission_label_hvac" msgid="1499454192558727843">"Accesează sistemul hvac al mașinii"</string>
<string name="car_permission_desc_hvac" msgid="3754229695589774195">"Accesează sistemul hvac al mașinii."</string>
<string name="car_permission_label_mileage" msgid="4661317074631150551">"Accesează informațiile despre kilometrajul mașinii"</string>
@@ -35,7 +35,7 @@
<string name="car_permission_label_vehicle_dynamics_state" msgid="313779267420048367">"Accesează starea dinamică a mașinii"</string>
<string name="car_permission_desc_vehicle_dynamics_state" msgid="8891506193446375660">"Accesează starea dinamică a mașinii."</string>
<string name="car_permission_label_vendor_extension" msgid="7141601811734127361">"Accesează canalul furnizorului mașinii"</string>
- <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesează canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
+ <string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Accesați canalul furnizorului auto pentru a face schimb de informații specifice mașinii."</string>
<string name="car_permission_label_radio" msgid="6009465291685935112">"Controlează radioul mașinii"</string>
<string name="car_permission_desc_radio" msgid="3385999027478186964">"Accesează radioul mașinii."</string>
<string name="car_permission_label_projection" msgid="9107156380287576787">"Proiectează o interfață de pe un telefon pe afișajul mașinii"</string>
@@ -45,23 +45,23 @@
<string name="car_permission_label_audio_volume" msgid="310587969373137690">"Controlează volumul audio din mașină"</string>
<string name="car_permission_label_audio_settings" msgid="6524703796944023977">"Gestionează setările audio ale mașinii"</string>
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"Imită nivelul HAL al vehiculului"</string>
- <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primești evenimente de reducere a volumului audio"</string>
+ <string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"Primiți evenimente de reducere a volumului audio"</string>
<string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"Permite notificarea unei aplicații atunci când volumul acesteia este redus din cauza redării unui alt conținut audio în mașină."</string>
<string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"Imită nivelul HAL al mașinii pentru testare internă."</string>
<string name="car_permission_desc_audio_volume" msgid="536626185654307889">"Controlează volumul audio din mașină."</string>
- <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlează setările audio ale mașinii"</string>
+ <string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Controlați setările audio ale mașinii"</string>
<string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Blocarea aplicațiilor"</string>
- <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduci."</string>
+ <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Controlează blocarea aplicațiilor în timp ce conduceți."</string>
<string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Manager de navigare"</string>
<string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Raportează datele de navigare la grupul de instrumente"</string>
<string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Redare directă pe grupul de instrumente"</string>
- <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permite unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
+ <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"Permiteți unei aplicații să declare activitățile de afișat în grupul de instrumente"</string>
<string name="car_permission_car_cluster_control" msgid="1382247204230165674">"Control pentru grupul de instrumente"</string>
- <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansează aplicațiile din grupul de instrumente"</string>
+ <string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"Lansați aplicațiile din grupul de instrumente"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"Starea de navigare în grupul de instrumente"</string>
- <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultează modificările stării de navigare în grupul de instrumente"</string>
+ <string name="car_permission_desc_car_monitor_cluster_navigation_state" msgid="8745047153878713339">"Ascultați modificările stării de navigare în grupul de instrumente"</string>
<string name="car_permission_label_car_ux_restrictions_configuration" msgid="6801393970411049725">"Configurarea restricțiilor UX"</string>
- <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurează restricțiile UX"</string>
+ <string name="car_permission_desc_car_ux_restrictions_configuration" msgid="5711926927484813777">"Configurați restricțiile UX"</string>
<string name="car_permission_label_access_private_display_id" msgid="6712116114341634316">"Acces pentru citire la ID-ul de afișare privată"</string>
<string name="car_permission_desc_access_private_display_id" msgid="8535974477610944721">"Permite acces pentru citire la ID-ul de afișare privată"</string>
<string name="car_permission_label_car_handle_usb_aoap_device" msgid="72783989504378036">"Comunică cu dispozitivul USB în modul AOAP"</string>
@@ -82,18 +82,18 @@
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"Monitorizează utilizarea stocării flash"</string>
<string name="car_permission_label_driving_state" msgid="7754624599537393650">"Ascultă starea La volan"</string>
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ascultă modificările stării La volan."</string>
- <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosește serviciul de telemetrie al mașinii"</string>
- <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectează date despre starea sistemului mașinii"</string>
- <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosește serviciul EVS al mașinii"</string>
- <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonează-te la streamurile video EVS"</string>
- <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicită activitatea de previzualizare EVS"</string>
- <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicită sistemului să lanseze activitatea de previzualizare EVS"</string>
- <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionează activitatea de previzualizare EVS"</string>
- <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionează activitatea de previzualizare EVS a sistemului"</string>
- <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosește camera EVS"</string>
- <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonează-te la streamurile camerei EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizează starea serviciului EVS"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmărește modificările de stare ale serviciului EVS"</string>
+ <string name="car_permission_label_use_telemetry_service" msgid="948005838683758846">"Folosiți serviciul de telemetrie al mașinii"</string>
+ <string name="car_permission_desc_use_telemetry_service" msgid="3633214312435700766">"Colectați date despre starea sistemului mașinii"</string>
+ <string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Folosiți serviciul EVS al mașinii"</string>
+ <string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonați-vă la streamurile video EVS"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitați activitatea de previzualizare EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitați sistemului să lanseze activitatea de previzualizare EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Gestionați activitatea de previzualizare EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Gestionați activitatea de previzualizare EVS a sistemului"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Folosiți camera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonați-vă la streamurile camerei EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizați starea serviciului EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Urmăriți modificările de stare ale serviciului EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"Accesează informațiile detaliate despre motorul mașinii"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accesează informațiile detaliate despre motorul mașinii"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesează ușa de alimentare a mașinii și portul de încărcare"</string>
@@ -114,12 +114,12 @@
<string name="car_permission_desc_car_info" msgid="2118081474543537653">"Accesează informațiile de bază despre mașină."</string>
<string name="car_permission_label_privileged_car_info" msgid="1304018073760220785">"să acceseze informațiile cu acces privilegiat ale mașinii"</string>
<string name="car_permission_desc_privileged_car_info" msgid="2245117655328125350">"să acceseze informațiile cu acces privilegiat ale mașinii."</string>
- <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesează informațiile despre permisiuni ale furnizorului mașinii"</string>
- <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesează informațiile despre permisiuni ale furnizorului mașinii."</string>
+ <string name="car_permission_label_vendor_permission_info" msgid="4471260460536888654">"accesați informațiile despre permisiuni ale furnizorului mașinii"</string>
+ <string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"Accesați informațiile despre permisiuni ale furnizorului mașinii."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"Citește starea luminilor exterioare ale mașinii"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Accesează starea luminilor exterioare ale mașinii."</string>
- <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesează datele temporale ale mașinii"</string>
- <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesează datele temporale ale mașinii."</string>
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"accesați datele temporale ale mașinii"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Accesați datele temporale ale mașinii."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"accesează sursa de legătură a criptării mașinii"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Accesează sursa de legătură a criptării mașinii."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"Citește starea luminilor exterioare ale mașinii"</string>
@@ -142,32 +142,30 @@
<string name="car_permission_desc_car_powertrain" msgid="1116007372551797796">"Accesează informațiile powertrain ale mașinii."</string>
<string name="car_permission_label_car_power" msgid="8111448088314368268">"Citește starea de încărcare a mașinii"</string>
<string name="car_permission_desc_car_power" msgid="9202079903668652864">"Accesează starea de încărcare a mașinii."</string>
- <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrie un dispozitiv de încredere"</string>
- <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permite înscrierea unui dispozitiv de încredere"</string>
- <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlează modul de testare a mașinii"</string>
- <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlează modul de testare a mașinii"</string>
- <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activează sau dezactivează funcțiile mașinii"</string>
- <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activează sau dezactivează funcțiile mașinii."</string>
- <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosește ceasul de gardă al mașinii"</string>
- <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosește ceasul de gardă al mașinii."</string>
- <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionează configurația ceasului de gardă al mașinii"</string>
- <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionează configurația ceasului de gardă al mașinii."</string>
- <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adună valori de la ceasul de gardă al mașinii"</string>
- <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adună valori de la ceasul de gardă al mașinii."</string>
- <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citește politica pentru încărcarea mașinii"</string>
- <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citește politica pentru încărcarea mașinii."</string>
- <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlează politica pentru încărcarea mașinii"</string>
- <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlează politica pentru încărcarea mașinii."</string>
+ <string name="car_permission_label_enroll_trust" msgid="3512907900486690218">"Înscrieți un dispozitiv de încredere"</string>
+ <string name="car_permission_desc_enroll_trust" msgid="4148649994602185130">"Permiteți înscrierea unui dispozitiv de încredere"</string>
+ <string name="car_permission_label_car_test_service" msgid="9159328930558208708">"Controlați modul de testare a mașinii"</string>
+ <string name="car_permission_desc_car_test_service" msgid="7426844534110145843">"Controlați modul de testare a mașinii"</string>
+ <string name="car_permission_label_control_car_features" msgid="3905791560378888286">"Activați sau dezactivați funcțiile mașinii"</string>
+ <string name="car_permission_desc_control_car_features" msgid="7646711104530599901">"Activați sau dezactivați funcțiile mașinii."</string>
+ <string name="car_permission_label_use_car_watchdog" msgid="6973938293170413475">"folosiți ceasul de gardă al mașinii"</string>
+ <string name="car_permission_desc_use_car_watchdog" msgid="8244592601805516086">"Folosiți ceasul de gardă al mașinii."</string>
+ <string name="car_permission_label_control_car_watchdog_config" msgid="7002301555689209243">"gestionați configurația ceasului de gardă al mașinii"</string>
+ <string name="car_permission_desc_control_car_watchdog_config" msgid="2276721198186100781">"Gestionați configurația ceasului de gardă al mașinii."</string>
+ <string name="car_permission_label_collect_car_watchdog_metrics" msgid="6868646053065666480">"adunați valori de la ceasul de gardă al mașinii"</string>
+ <string name="car_permission_desc_collect_car_watchdog_metrics" msgid="5712074376194601441">"Adunați valori de la ceasul de gardă al mașinii."</string>
+ <string name="car_permission_label_read_car_power_policy" msgid="4597484321338979324">"citiți politica pentru încărcarea mașinii"</string>
+ <string name="car_permission_desc_read_car_power_policy" msgid="5430714179790601808">"Citiți politica pentru încărcarea mașinii."</string>
+ <string name="car_permission_label_control_car_power_policy" msgid="6840069695926008330">"controlați politica pentru încărcarea mașinii"</string>
+ <string name="car_permission_desc_control_car_power_policy" msgid="8565782440893507028">"Controlați politica pentru încărcarea mașinii."</string>
<string name="car_permission_label_adjust_shutdown_process" msgid="184826150481255557">"să ajusteze procesul de închidere"</string>
- <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustează procesul de închidere."</string>
- <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redă șabloane"</string>
- <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redă șabloane."</string>
+ <string name="car_permission_desc_adjust_shutdown_process" msgid="5059212045073049971">"Ajustați procesul de închidere."</string>
+ <string name="car_permission_label_template_renderer" msgid="3464887382919754850">"redați șabloane"</string>
+ <string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Redați șabloane."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"să controleze aplicațiile lansate"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Controlează aplicațiile lansate."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"gestionează prioritatea firelor"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Gestionează prioritatea firelor."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Magistrala CAN nu a reușit"</string>
- <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectează și reconectează unitatea radio, apoi repornește mașina"</string>
+ <string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Magistrala CAN nu răspunde. Deconectați și reconectați unitatea radio, apoi reporniți mașina"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Dispozitivul meu"</string>
<string name="default_guest_name" msgid="2912812799433131476">"Invitat"</string>
</resources>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index 2a5c933..25a767b 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="car_permission_label" msgid="2215078736675564541">"Данные автомобиля"</string>
- <string name="car_permission_desc" msgid="3584369074931334964">"получать доступ к данным автомобиля."</string>
+ <string name="car_permission_desc" msgid="3584369074931334964">"Доступ к данным автомобиля"</string>
<string name="car_permission_label_camera" msgid="3725702064841827180">"доступ к камере автомобиля"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Доступ к камерам автомобиля"</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"доступ к данным об энергоресурсах автомобиля"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Обработка шаблонов."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"управление запуском приложений"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Управление запуском приложений."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управление приоритетом цепочек"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управление приоритетом цепочек"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Произошла ошибка шины CAN."</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Шина CAN не отвечает. Переподключите коннектор, а затем выключите зажигание и заведите машину снова."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мое устройство"</string>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index a624b77..8c01b49 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"අච්චු විදහන්න."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"යෙදුම් දියත් කිරීම කළමනාකරණය කරන්න."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"පොට ප්රමුඛතාවය කළමනාකරණය කරන්න"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"පොට ප්රමුඛතාවය කළමනාකරණය කරන්න."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN බස් අසාර්ථකයි"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN බස් ප්රතිචාර නොදක්වයි. හෙඩ්යුනිට් පෙට්ටිය පේනු ඉවත් කර ආපසු පේනුගත කර, මෝටර් රථය යළි අරඹන්න"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"මගේ උපාංගය"</string>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index e88b08e..886ba76 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Vykresľovanie šablón."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ovládanie spúšťaných aplikácií"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ovládanie spúšťaných aplikácií."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"správa priority vlákna"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Správa priority vlákna."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Zbernica CAN zlyhala"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Zbernica CAN nereaguje. Odpojte autorádio a znova ho pripojte. Potom auto znova naštartujte."</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moje zariadenie"</string>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 3911ed3..0271b10b 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Upodabljanje predlog."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"nadziranje zaganjanja aplikacij"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Nadziranje zaganjanja aplikacij"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"upravljanje prednosti niti"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Upravljanje prednosti niti."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Napaka vodila CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Vodilo CAN se ne odziva. Odklopite in znova priklopite ohišje avtomobilskega vmesnika ter znova zaženite avtomobil"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Moja naprava"</string>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index 9a9a1e6..814a2ca 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Të paraqesë shabllonet."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrollo hapjen e aplikacioneve"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrollo hapjen e aplikacioneve."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"menaxho përparësinë në bashkëbisedim"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Menaxho përparësinë në bashkëbisedim."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Kanali i komunikimit CAN dështoi"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kanali i komunikimit CAN nuk përgjigjet. Shkëput dhe lidh përsëri kutinë e njësisë kryesore dhe rindiz makinës"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Pajisja ime"</string>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index daad63f..c4bdc06 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Приказивање шаблона."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"контрола покретања апликација"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Контролише покретање апликација."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"управљање приоритетом нити"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Управљање приоритетом нити."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Грешка CAN магистрале"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN магистрала не реагује. Искључите и поново укључите главну јединицу и поново покрените аутомобил"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мој уређај"</string>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index 083411d..623e197 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Rendera mallar."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"styr startande appar"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Styr startande appar."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"hantera trådprioritet"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Hantera trådprioritet."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Fel i CAN-bussen"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-bussen svarar inte. Koppla från huvudenheten och koppla in den igen. Starta sedan om bilen"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Min enhet"</string>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index e0572bf..08cac41 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Kutekeleza violezo."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kudhibiti programu za kufungua"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Dhibiti programu za kufungua."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"dhibiti kipaumbele cha mazungumzo"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Dhibiti kipaumbele cha mazungumzo."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Imeshindwa kuleta maelezo ya kebo CAN"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Kebo ya CAN haifanyi kazi. Ondoa kisha urudishe tena kisanduku cha sehemu kuu na uzime kisha uwashe gari"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Kifaa Changu"</string>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index c0e6781..4b9987f 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"டெம்ப்ளேட்டுகளைக் காட்டுதல்."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"தொடங்கும் ஆப்ஸைக் கட்டுப்படுத்தலாம்."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"மெசேஜ் தொடருக்கான முன்னுரிமையை நிர்வகித்தல்."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN bus அமைப்பு தோல்வியடைந்தது"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN bus அமைப்பு இயங்கவில்லை. ஹெட்யூனிட் பாக்ஸைப் பிளக்கில் இருந்து அகற்றிச் செருகியபின் காரை மீண்டும் தொடங்கவும்"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"எனது சாதனம்"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index 7462cc2..3dc67d3 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -53,9 +53,9 @@
<string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"యాప్ బ్లాక్ చేయడం"</string>
<string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"డ్రైవింగ్లో ఉన్నప్పుడు అప్లికేషన్లను బ్లాక్ చేయండి"</string>
<string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"నావిగేషన్ మేనేజర్"</string>
- <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గ్రూపునకు నావిగేషన్ డేటాను రిపోర్ట్ చేయండి"</string>
- <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గ్రూపునకు ప్రత్యక్ష రెండరింగ్"</string>
- <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గ్రూపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్ను అనుమతించండి."</string>
+ <string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"పరికర గుంపుకు నావిగేషన్ డేటాని రిపోర్ట్ చేయండి"</string>
+ <string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"పరికర గుంపుకు ప్రత్యక్ష రెండరింగ్"</string>
+ <string name="car_permission_desc_car_display_in_cluster" msgid="2668300546822672927">"పరికర గుంపులో ప్రదర్శించాల్సిన కార్యకలాపలని తెలియచెప్పడానికి అప్లికేషన్ను అనుమతించండి."</string>
<string name="car_permission_car_cluster_control" msgid="1382247204230165674">"పరికర గుంపు నియంత్రణ"</string>
<string name="car_permission_desc_car_cluster_control" msgid="9222776665281176031">"పరికర గుంపు యాప్లను ప్రారంభించండి"</string>
<string name="car_permission_car_monitor_cluster_navigation_state" msgid="7025307242306902441">"పరికర క్లస్టర్ నావిగేషన్ స్టేట్"</string>
@@ -74,9 +74,9 @@
<string name="car_permission_desc_diag_read" msgid="1121426363040966178">"కారు నుండి విశ్లేషణ డేటాను తెలుసుకోగలవు."</string>
<string name="car_permission_label_diag_clear" msgid="4783070510879698157">"సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు"</string>
<string name="car_permission_desc_diag_clear" msgid="7453222114866042786">"కారు నుండి సమస్య విశ్లేషణ డేటాను క్లియర్ చేయగలవు."</string>
- <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS పబ్లిషర్"</string>
+ <string name="car_permission_label_vms_publisher" msgid="3049934078926106641">"VMS ప్రచురణకర్త"</string>
<string name="car_permission_desc_vms_publisher" msgid="5589489298597386828">"VMS మెసేజ్లను పబ్లిష్ చేయండి"</string>
- <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సబ్స్క్రయిబర్"</string>
+ <string name="car_permission_label_vms_subscriber" msgid="5648841182059222299">"VMS సభ్యులు"</string>
<string name="car_permission_desc_vms_subscriber" msgid="7551009457847673620">"VMS మెసేజ్లను పొందడానికి సబ్స్క్రయిబ్ చేయండి"</string>
<string name="car_permission_label_storage_monitoring" msgid="2327639346522530549">"ఫ్లాష్ నిల్వ పర్యవేక్షణ"</string>
<string name="car_permission_desc_storage_monitoring" msgid="2075712271139671318">"ఫ్లాష్ నిల్వ వినియోగాన్ని పర్యవేక్షించండి"</string>
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"టెంప్లేట్లను రెండర్ చేస్తుంది."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"లాంచ్ చేయబడుతున్న యాప్లను కంట్రోల్ చేయండి"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"లాంచ్ చేయబడుతున్న యాప్లను కంట్రోల్ చేయండి."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"థ్రెడ్ ప్రాధాన్యతను మేనేజ్ చేయడానికి అనుమతి ఇవ్వండి."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN బస్సు విఫలమైంది"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN బస్సు స్పందించలేదు. హెడ్ యూనిట్ బాక్స్ని ప్లగ్ మరియు అన్ప్లగ్ చేసి కారుని పునఃప్రారంభించుము"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"నా పరికరం"</string>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index 101f655..b04eabe 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"แสดงผลเทมเพลต"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"ควบคุมการเปิดใช้งานแอปพลิเคชัน"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"จัดการลำดับความสำคัญของชุดข้อความ"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN Bus ล้มเหลว"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN Bus ไม่ตอบสนอง ถอดปลั๊กกล่องเครื่องเล่นวิทยุ (Headunit) แล้วเสียบกลับเข้าไป สตาร์ทรถอีกครั้ง"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"อุปกรณ์ของฉัน"</string>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index 7b67373..e51e12e 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mag-render ng mga template."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kontrolin ang paglunsad ng mga application"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kontrolin ang paglunsad ng mga application."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"pamahalaan ang priyoridad ng thread"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Pamahalaan ang priyoridad ng thread."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Hindi gumana ang CAN bus"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Hindi tumugon ang CAN bus. Hugutin at muling isaksak ang headunit box at i-restart ang sasakyan"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Aking Device"</string>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 1e9bb9a..176b227 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Şablonları oluşturma."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"başlatılan uygulamaları kontrol etme"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Başlatılan uygulamaları kontrol etme."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"ileti dizisi önceliğini yönetin."</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"İleti dizisi önceliğini yönetin."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN veri yolu başarısız"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN veri yolu yanıt vermiyor. Ana birim kutusunu söküp tekrar takın ve aracı yeniden çalıştırın"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Cihazım"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 2bb9307..070e447 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Відображати шаблони."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"керувати додатками, що запускаються"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Керувати додатками, що запускаються."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"керувати пріоритетом ланцюжка"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Керувати пріоритетом ланцюжка."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Помилка CAN-шини"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN-шина не відповідає. Від’єднайте та знову під’єднайте головний пристрій аудіосистеми й заведіть автомобіль ще раз"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Мій пристрій"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index a28b091..2047e43 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"تمثیلات تیار کریں۔"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"شروع ہونے والی ایپلیکیشنز کو کنٹرول کریں۔"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"سلسلے کی ترجیح کا نظم کریں"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"سلسلے کی ترجیح کا نظم کریں۔"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"کین بس ناکام ہو گئی"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"کین بس جواب نہیں دیتی ہے۔ ہیڈیونٹ باکس کو ان پلگ کر کے دوبارہ پلگ کریں اور کار کو دوبارہ شروع کریں"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"میرا آلہ"</string>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 1dc37e8..5c9e233 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Andozalarni renderlash."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"ilovani ishga tushirishni boshqarish"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Ilovani ishga tushirishni boshqarish."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"mavzu ustuvorligini boshqarish"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Mavzu ustuvorligini boshqarish."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN shinalarida xatolik yuz berdi"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN javob bermayapti. Konnektorni chiqaring va qayta ulang, keyin avtomobilni oʻt oldiring"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Qurilmam"</string>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index 9804c65..c92ddc3 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Mẫu kết xuất hình ảnh."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"kiểm soát việc mở ứng dụng"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Kiểm soát việc mở ứng dụng."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"quản lý mức độ ưu tiên của chuỗi"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Quản lý mức độ ưu tiên của chuỗi."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Đường dẫn chính CAN không hoạt động"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Đường dẫn chính CAN không phản hồi. Rút rồi cắm lại hộp bộ đầu và khởi động lại ô tô"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Thiết bị của tôi"</string>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index 70d371f..e401aca 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"渲染模板。"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制应用启动"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制应用启动。"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理会话优先级"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理会话优先级。"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"CAN 总线故障"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"CAN 总线没有响应。请将主机盒插头拔下并插回,然后重新启动汽车"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的设备"</string>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index a42a8c0..fc2b163 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"輸出範本。"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制啟動應用程式"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制啟動應用程式。"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理郵件串優先次序"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理郵件串優先次序。"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路操作失敗"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路未有回覆。請拔除並重新插上汽車音響主機,然後重新啟動汽車"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index ad7d0f6..4d8809e 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"算繪範本。"</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"控制要啟動的應用程式"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"控制要啟動的應用程式。"</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"管理會話串優先順序"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"管理會話串優先順序。"</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"控制器區域網路發生問題"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"控制器區域網路無回應。請將主機盒插頭拔下並插回,然後重新啟動車輛"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"我的裝置"</string>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index c3e0af4..406f309 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -164,8 +164,6 @@
<string name="car_permission_desc_template_renderer" msgid="6047233999260920122">"Nikezela izifanekiso."</string>
<string name="car_permission_label_control_car_app_launch" msgid="214632389637409226">"lawula ama-application okuqalisa"</string>
<string name="car_permission_desc_control_car_app_launch" msgid="4245527461733374198">"Lawula ama-application okuqalisa."</string>
- <string name="car_permission_label_manage_thread_priority" msgid="6775846409863509575">"phatha okubalulekile kochungechunge"</string>
- <string name="car_permission_desc_manage_thread_priority" msgid="3833845502119615929">"Phatha okubalulekile kochungechunge."</string>
<string name="car_can_bus_failure" msgid="2334035748788283914">"Ibhasi ye-CAN yehlulekile"</string>
<string name="car_can_bus_failure_desc" msgid="4125516222786484733">"Ibhasi ye-CAN ayiphenduli. Nqamula futhi uxhume ibhokisi le-headunit ukuze uqalise kabusha imoto"</string>
<string name="trust_device_default_name" msgid="4213625926070261253">"Idivayisi yami"</string>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 460935d..36464a5 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -490,4 +490,38 @@
<!-- How many milli-seconds CarService should wait before managing pre-created users after
system start. This property only applied when config_userPreCreationStage flag is 2. -->
<integer name="config_userPreCreationDelay">5000</integer>
+
+ <!-- This is the component name for the OEM customization service. OEM can choose to implement
+ this service to customize car service behavior for different policies. If OEMs choose to
+ implement it, they have to implement a service extending OemCarService exposed by car-lib,
+ and implement the needed component services.
+ If the component name is invalid, CarService would not connect to any OEM service.
+ Component name can not be a third party package. It should be pre-installed -->
+ <string name="config_oemCarService" translatable="false"></string>
+
+ <!-- Related to OEM customization service. How many milliseconds CarService should wait for
+ OEM service to connect. If `config_oemCarService` is set and oem service package exists,
+ then CarService would wait for this much time for OEM service to connect. If OEM service
+ doesn't connect within this time, CarService would crash itself. -->
+ <integer name="config_oemCarService_connection_timeout_ms">5000</integer>
+
+ <!-- Related to OEM customization service. How many milliseconds CarService should wait for
+ OEM service to be ready. This is the wait time after OEM service is connected to
+ CarService. CarService would poll OEM service for being ready, if OEM service not ready
+ within timeout, CarService would crash. -->
+ <integer name="config_oemCarService_serviceReady_timeout_ms">5000</integer>
+
+ <!-- Related to OEM customization service. Default timeout for calls made by CarService to
+ OEM service. After this, CarService would timeout the call. If OEM service returns the
+ results after timeout, it would be ignored. -->
+ <integer name="config_oemCarService_regularCall_timeout_ms">5000</integer>
+
+ <!-- Related to OEM customization service. Default timeout for critical calls made by CarService
+ to OEM service. After this timeout, CarService would itself and OEM Service. -->
+ <integer name="config_oemCarService_crashCall_timeout_ms">10000</integer>
+
+ <!-- Related to OEM customization service. Default thread pool size for communicating with the
+ OEM Service. The value can only be between 8 and 16. If value is higher than 16, thread
+ pool size will be 16. If value is lower than 8, thread pool size will be 8.-->
+ <integer name="config_oemCarService_thread_pool_size">8</integer>
</resources>
diff --git a/service/res/values/overlayable.xml b/service/res/values/overlayable.xml
index 449fde2..2cc338b 100644
--- a/service/res/values/overlayable.xml
+++ b/service/res/values/overlayable.xml
@@ -108,6 +108,12 @@
<item type="bool" name="config_enableExternalCarTimeToExternalTimeSuggestion"/>
<item type="integer" name="config_userPreCreationStage"/>
<item type="integer" name="config_userPreCreationDelay"/>
+ <item type="string" name="config_oemCarService" translatable="false"/>
+ <item type="integer" name="config_oemCarService_connection_timeout_ms"/>
+ <item type="integer" name="config_oemCarService_serviceReady_timeout_ms"/>
+ <item type="integer" name="config_oemCarService_regularCall_timeout_ms"/>
+ <item type="integer" name="config_oemCarService_crashCall_timeout_ms"/>
+ <item type="integer" name="config_oemCarService_thread_pool_size"/>
<!-- Params from config.xml that can be overlaid -->
<!-- XML files that can be overlaid -->
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index b3f0d11..697d09c 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -33,6 +33,10 @@
<string name="car_permission_label_control_car_energy">Control car\u2019s EV charge settings</string>
<!-- Permission text: can control your car's EV charge settings [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_control_car_energy">Control your car\u2019s EV charge settings.</string>
+ <!-- Permission text: can control oem car service binding [CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_bind_oem_car_service" translatable="false">Controls OEM Car Service binding</string>
+ <!-- Permission text: can control oem car service binding [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_bind_oem_car_service" translatable="false">Controls which service can bind to OemCarService</string>
<!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
<string name="car_permission_label_adjust_range_remaining">adjust car\u2019s range remaining</string>
<!-- Permission text: can adjust value of your car's range remaining [CHAR LIMIT=NONE] -->
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index 784f05d..e2cf486 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -36,7 +36,6 @@
import android.car.hardware.power.ICarPowerPolicyListener;
import android.car.hardware.power.PowerComponent;
import android.car.media.CarMediaManager;
-import android.car.media.CarMediaManager.MediaSourceChangedListener;
import android.car.media.CarMediaManager.MediaSourceMode;
import android.car.media.ICarMedia;
import android.car.media.ICarMediaSourceListener;
@@ -860,12 +859,16 @@
.equals(mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK])) {
mRemovedMediaSourceComponents[MEDIA_SOURCE_MODE_PLAYBACK] = null;
}
+ startMediaConnectorService(
+ shouldStartPlayback(mPlayOnMediaSourceChangedConfig),
+ UserHandle.of(ActivityManager.getCurrentUser()));
+ } else {
+ Slogf.i(
+ CarLog.TAG_MEDIA,
+ "Media source is null, skip starting media connector service");
}
notifyListeners(MEDIA_SOURCE_MODE_PLAYBACK);
-
- startMediaConnectorService(shouldStartPlayback(mPlayOnMediaSourceChangedConfig),
- UserHandle.of(ActivityManager.getCurrentUser()));
// Reset current playback state for the new source, in the case that the app is in an error
// state (e.g. not signed in). This state will be updated from the app callback registered
// below, to make sure mCurrentPlaybackState reflects the current source only.
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
index ece2a1e..19f63fd 100644
--- a/service/src/com/android/car/CarTestService.java
+++ b/service/src/com/android/car/CarTestService.java
@@ -103,6 +103,11 @@
releaseToken(token);
}
+ @Override
+ public String getOemServiceName() {
+ return mICarImpl.getOemServiceName();
+ }
+
private void releaseToken(IBinder token) {
Slogf.d(TAG, "releaseToken, token: " + token);
synchronized (mLock) {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index f35c745..aa21108 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -75,6 +75,7 @@
import com.android.car.internal.ICarServiceHelper;
import com.android.car.internal.ICarSystemServerClient;
import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.car.oem.CarOemProxyService;
import com.android.car.os.CarPerformanceService;
import com.android.car.pm.CarPackageManagerService;
import com.android.car.power.CarPowerManagementService;
@@ -117,6 +118,7 @@
private final SystemInterface mSystemInterface;
+ private final CarOemProxyService mCarOemService;
private final SystemActivityMonitoringService mSystemActivityMonitoringService;
private final CarPowerManagementService mCarPowerManagementService;
private final CarPackageManagerService mCarPackageManagerService;
@@ -207,6 +209,10 @@
} else {
mCarServiceBuiltinPackageContext = builtinContext;
}
+
+ mCarOemService = constructWithTrace(t, CarOemProxyService.class,
+ () -> new CarOemProxyService(serviceContext));
+
mSystemInterface = systemInterface;
CarLocalServices.addService(SystemInterface.class, mSystemInterface);
mHal = constructWithTrace(t, VehicleHal.class,
@@ -487,8 +493,10 @@
service.init();
t.traceEnd();
}
+ t.traceBegin("CarOemService.initComplete");
+ mCarOemService.onInitComplete();
+ t.traceEnd();
t.traceEnd(); // "CarService.initAllServices"
-
t.traceEnd(); // "ICarImpl.init"
}
@@ -736,6 +744,7 @@
dumpAllHals(writer);
return;
}
+
int length = args.length - 1;
String[] halNames = new String[length];
System.arraycopy(args, 1, halNames, 0, length);
@@ -747,6 +756,13 @@
} else if ("--data-dir".equals(args[0])) {
dumpDataDir(writer);
return;
+ } else if ("--oem-service".equals(args[0])) {
+ if (args.length > 1 && args[1].equalsIgnoreCase("--name-only")) {
+ writer.println(getOemServiceName());
+ } else {
+ dumpOemService(writer);
+ }
+ return;
} else if ("--help".equals(args[0])) {
showDumpHelp(writer);
} else {
@@ -754,6 +770,22 @@
}
}
+ private void dumpOemService(IndentingPrintWriter writer) {
+ mCarOemService.dump(writer);
+ }
+
+ public String getOemServiceName() {
+ return mCarOemService.getOemServiceName();
+ }
+
+ private void dumpAll(IndentingPrintWriter writer) {
+ writer.println("*Dump car service*");
+ dumpVersions(writer);
+ dumpAllServices(writer);
+ dumpAllHals(writer);
+ dumpRROs(writer);
+ }
+
private void dumpRROs(IndentingPrintWriter writer) {
writer.println("*Dump Car Service RROs*");
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index c1026dd..142e7b3 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -467,11 +467,7 @@
return ERROR_BUSY;
}
- if (callback != null) {
- stopVideoStreamAndUnregisterCallback(callback);
- } else {
- stopService();
- }
+ stopService(callback);
break;
default:
@@ -600,6 +596,7 @@
if (mStreamCallback != null) {
// keep old reference for Runnable.
ICarEvsStreamCallback previousCallback = mStreamCallback;
+ mStreamCallback = null;
mHandler.post(() -> notifyStreamStopped(previousCallback));
}
@@ -684,7 +681,7 @@
// Stops a current video stream and unregisters a callback
private void stopVideoStreamAndUnregisterCallback(ICarEvsStreamCallback callback) {
synchronized (mLock) {
- if (callback.asBinder() != mStreamCallback.asBinder()) {
+ if (callback == null || callback.asBinder() != mStreamCallback.asBinder()) {
Slogf.i(TAG_EVS, "Declines a request to stop a video not from a current client.");
return;
}
@@ -1023,7 +1020,6 @@
public void stopVideoStream(@NonNull ICarEvsStreamCallback callback) {
CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_EVS_CAMERA);
Objects.requireNonNull(callback);
-
synchronized (mLock) {
if (mStreamCallback == null || callback.asBinder() != mStreamCallback.asBinder()) {
Slogf.i(TAG_EVS, "Ignores a video stream request not from current stream client.");
@@ -1243,16 +1239,32 @@
/** Stops a current service */
private void stopService() {
+ stopService(/* callback= */ null);
+ }
+
+ private void stopService(ICarEvsStreamCallback callback) {
try {
+ synchronized (mLock) {
+ if (callback != null && callback.asBinder() != mStreamCallback.asBinder()) {
+ Slogf.w(TAG_EVS, "Decline a request to stop a video from an unknown client.");
+ return;
+ }
+
+ unlinkToDeathStreamCallbackLocked();
+ mStreamCallback = null;
+ }
+ Slogf.i(TAG_EVS, "Last stream client has been disconnected.");
+
+ // Notify the client that the stream has ended.
+ if (callback != null) {
+ notifyStreamStopped(callback);
+ }
+
+ // Request to stop a video stream if it is active.
mHalWrapper.requestToStopVideoStream();
} catch (RuntimeException e) {
Slogf.w(TAG_EVS, Log.getStackTraceString(e));
} finally {
- // Unregister all stream callbacks.
- synchronized (mLock) {
- mStreamCallback = null;
- }
-
// We simply drop all buffer records; the native method will return all pending buffers
// to the native Extended System View service if it is alive.
synchronized (mBufferRecords) {
@@ -1261,6 +1273,9 @@
// Cancel a pending message to check a request timeout
mHandler.removeCallbacks(mActivityRequestTimeoutRunnable);
+
+ // Close current camera
+ mHalWrapper.closeCamera();
}
}
diff --git a/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
new file mode 100644
index 0000000..ae55a45
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemAudioFocusProxyService.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+import android.car.builtin.util.Slogf;
+import android.car.oem.IOemCarAudioFocusService;
+import android.media.AudioFocusInfo;
+import android.os.RemoteException;
+
+import com.android.car.CarLog;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Provides functionality of the OEM Audio Focus Service.
+ */
+public final class CarOemAudioFocusProxyService {
+
+ private static final String TAG = CarLog.tagFor(CarOemAudioFocusProxyService.class);
+ private static final String CALLER_TAG = CarLog.tagFor(CarOemAudioFocusProxyService.class);
+
+ private final CarOemProxyServiceHelper mHelper;
+ private final IOemCarAudioFocusService mOemCarAudioFocusService;
+
+ public CarOemAudioFocusProxyService(CarOemProxyServiceHelper helper,
+ IOemCarAudioFocusService oemAudioFocusService) {
+ mHelper = helper;
+ mOemCarAudioFocusService = oemAudioFocusService;
+ }
+
+ /**
+ * Updates audio focus changes.
+ */
+ public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+ List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+ mHelper.doBinderOneWayCall(CALLER_TAG, () -> {
+ try {
+ mOemCarAudioFocusService
+ .audioFocusChanged(currentFocusHolders, currentFocusLosers, zoneId);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, e,
+ "audioFocusChanged call received RemoteException- currentFocusHolders:%s, "
+ + "currentFocusLosers:%s, ZoneId: %s, , calling to crash CarService",
+ currentFocusHolders, currentFocusLosers, zoneId);
+ }
+ });
+ }
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyService.java b/service/src/com/android/car/oem/CarOemProxyService.java
new file mode 100644
index 0000000..5624267
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyService.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+import android.annotation.Nullable;
+import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.builtin.os.BuildHelper;
+import android.car.builtin.util.Slogf;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarService;
+import android.car.oem.IOemCarServiceCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.car.CarServiceUtils;
+import com.android.car.R;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Manages access to OemCarService.
+ *
+ * <p>All calls in this class are blocking on OEM service initialization, so should be called as
+ * late as possible.
+ *
+ * <b>NOTE</b>: All {@link CarOemProxyService} call should be after init of ICarImpl. If any
+ * component calls {@link CarOemProxyService} before init of ICarImpl complete, it would throw
+ * {@link IllegalStateException}.
+ */
+public final class CarOemProxyService implements CarServiceBase {
+
+ private static final String TAG = CarOemProxyService.class.getSimpleName();
+ private static final String CALL_TAG = CarOemProxyService.class.getSimpleName();
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+ // mock component name for testing if system property is set.
+ private static final String PROPERTY_EMULATED_OEM_CAR_SERVICE =
+ "persist.com.android.car.internal.debug.oem_car_service";
+
+ private final int mOemServiceConnectionTimeoutMs;
+ private final int mOemServiceReadyTimeoutMs;
+ private final Object mLock = new Object();
+ private final boolean mIsFeatureEnabled;
+ private final Context mContext;
+ private final boolean mIsOemServiceBound;
+ private final CarOemProxyServiceHelper mHelper;
+ private final HandlerThread mHandlerThread;
+ private final Handler mHandler;
+ @GuardedBy("mLock")
+ private final ArrayList<CarOemProxyServiceCallback> mCallbacks = new ArrayList<>();
+
+
+ private String mComponentName;
+
+ // True once OemService return true for {@code isOemServiceReady} call. It means that OEM
+ // service has completed all the initialization and ready to serve requests.
+ @GuardedBy("mLock")
+ private boolean mIsOemServiceReady;
+ // True once OEM service is connected. It means that OEM service has return binder for
+ // communication. OEM service may still not be ready.
+ @GuardedBy("mLock")
+ private boolean mIsOemServiceConnected;
+
+ @GuardedBy("mLock")
+ private boolean mInitComplete;
+ @GuardedBy("mLock")
+ private IOemCarService mOemCarService;
+ @GuardedBy("mLock")
+ private CarOemAudioFocusProxyService mCarOemAudioFocusProxyService;
+
+ private final ServiceConnection mCarOemServiceConnection = new ServiceConnection() {
+
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ Slogf.i(TAG, "onServiceConnected: %s, %s", componentName, iBinder);
+ synchronized (mLock) {
+ if (mOemCarService == IOemCarService.Stub.asInterface(iBinder)) {
+ return; // already connected.
+ }
+ Slogf.i(TAG, "car oem service binder changed, was %s now: %s",
+ mOemCarService, iBinder);
+ mOemCarService = IOemCarService.Stub.asInterface(iBinder);
+ Slogf.i(TAG, "**CarOemService connected**");
+ mIsOemServiceConnected = true;
+ mLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ Slogf.e(TAG, "OEM service crashed. Crashing the CarService. ComponentName:%s",
+ componentName);
+ mHelper.crashCarService("Service Disconnected");
+ }
+ };
+
+ private final CountDownLatch mOemServiceReadyLatch = new CountDownLatch(1);
+
+ private final IOemCarServiceCallback mOemCarServiceCallback = new IOemCarServiceCallbackImpl();
+
+ @VisibleForTesting
+ public CarOemProxyService(Context context) {
+ this(context, null);
+ }
+
+ @VisibleForTesting
+ public CarOemProxyService(Context context, CarOemProxyServiceHelper helper) {
+ this(context, helper, null);
+ }
+
+ public CarOemProxyService(Context context, CarOemProxyServiceHelper helper, Handler handler) {
+ // Bind to the OemCarService
+ mContext = context;
+ Resources res = mContext.getResources();
+ mOemServiceConnectionTimeoutMs = res
+ .getInteger(R.integer.config_oemCarService_connection_timeout_ms);
+ mOemServiceReadyTimeoutMs = res
+ .getInteger(R.integer.config_oemCarService_serviceReady_timeout_ms);
+
+ String componentName = res.getString(R.string.config_oemCarService);
+
+ if (TextUtils.isEmpty(componentName)) {
+ // mock component name for testing if system property is set.
+ String emulatedOemCarService = SystemProperties.get(PROPERTY_EMULATED_OEM_CAR_SERVICE,
+ "");
+ if (!BuildHelper.isUserBuild() && emulatedOemCarService != null
+ && !emulatedOemCarService.isEmpty()) {
+ componentName = emulatedOemCarService;
+ Slogf.i(TAG, "Using emulated componentname for testing. ComponentName: %s",
+ mComponentName);
+ }
+ }
+
+ mComponentName = componentName;
+
+ Slogf.i(TAG, "Oem Car Service Config. Connection timeout:%s, Service Ready timeout:%d, "
+ + "component Name:%s", mOemServiceConnectionTimeoutMs, mOemServiceReadyTimeoutMs,
+ mComponentName);
+
+ if (isInvalidComponentName(context, mComponentName)) {
+ // feature disabled
+ mIsFeatureEnabled = false;
+ mIsOemServiceBound = false;
+ mHelper = null;
+ mHandlerThread = null;
+ mHandler = null;
+ Slogf.i(TAG, "**CarOemService is disabled.**");
+ return;
+ }
+
+ Intent intent = (new Intent())
+ .setComponent(ComponentName.unflattenFromString(mComponentName));
+
+ Slogf.i(TAG, "Binding to Oem Service with intent: %s", intent);
+ mHandlerThread = CarServiceUtils.getHandlerThread("car_oem_service");
+ mHandler = handler == null ? new Handler(mHandlerThread.getLooper()) : handler;
+
+ mIsOemServiceBound = mContext.bindServiceAsUser(intent, mCarOemServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM);
+
+ if (mIsOemServiceBound) {
+ mIsFeatureEnabled = true;
+ Slogf.i(TAG, "OemCarService bounded.");
+ } else {
+ mIsFeatureEnabled = false;
+ Slogf.e(TAG,
+ "Couldn't bound to OemCarService. Oem service feature is marked disabled.");
+ }
+ mHelper = helper == null ? new CarOemProxyServiceHelper(mContext) : helper;
+ }
+
+ private boolean isInvalidComponentName(Context context, String componentName) {
+ if (componentName == null || componentName.isEmpty()) {
+ if (DBG) {
+ Slogf.d(TAG, "ComponentName is null or empty.");
+ }
+ return true;
+ }
+
+ // Only pre-installed package can be used for OEM Service.
+ String packageName = ComponentName.unflattenFromString(componentName).getPackageName();
+ PackageInfo info;
+ try {
+ info = context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
+ } catch (NameNotFoundException e) {
+ Slogf.e(TAG, "componentName %s not found.", componentName);
+ return true;
+ }
+
+ if (info == null || info.applicationInfo == null
+ || !(PackageManagerHelper.isSystemApp(info.applicationInfo)
+ || PackageManagerHelper.isUpdatedSystemApp(info.applicationInfo)
+ || PackageManagerHelper.isOemApp(info.applicationInfo)
+ || PackageManagerHelper.isOdmApp(info.applicationInfo)
+ || PackageManagerHelper.isVendorApp(info.applicationInfo)
+ || PackageManagerHelper.isProductApp(info.applicationInfo)
+ || PackageManagerHelper.isSystemExtApp(info.applicationInfo))) {
+ if (DBG) {
+ Slogf.d(TAG, "Invalid component name. Info: %s", info);
+ }
+ return true;
+ }
+
+ if (DBG) {
+ Slogf.d(TAG, "Valid component name %s, ", componentName);
+ }
+
+ return false;
+ }
+
+ /**
+ * Registers callback to be called once OEM service is ready.
+ *
+ * <p>Other CarService components cannot call OEM service. But they can register a callback
+ * which would be called as soon as OEM Service is ready./
+ */
+ public void registerCallback(CarOemProxyServiceCallback callback) {
+ synchronized (mLock) {
+ mCallbacks.add(callback);
+ }
+ }
+
+ /**
+ * Informs if OEM service is enabled.
+ */
+ public boolean isOemServiceEnabled() {
+ synchronized (mLock) {
+ return mIsFeatureEnabled;
+ }
+ }
+
+ /**
+ * Informs if OEM service is ready.
+ */
+ public boolean isOemServiceReady() {
+ synchronized (mLock) {
+ return mIsOemServiceReady;
+ }
+ }
+
+ @Override
+ public void init() {
+ // Nothing to be done as OemCarService was initialized in the constructor.
+ }
+
+ @Override
+ public void release() {
+ // Stop OEM Service;
+ if (mIsOemServiceBound) {
+ Slogf.i(TAG, "Unbinding Oem Service");
+ mContext.unbindService(mCarOemServiceConnection);
+ }
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter writer) {
+ writer.println("***CarOemProxyService dump***");
+ writer.increaseIndent();
+ synchronized (mLock) {
+ writer.printf("mIsFeatureEnabled: %s\n", mIsFeatureEnabled);
+ writer.printf("mIsOemServiceBound: %s\n", mIsOemServiceBound);
+ writer.printf("mIsOemServiceReady: %s\n", mIsOemServiceReady);
+ writer.printf("mIsOemServiceConnected: %s\n", mIsOemServiceConnected);
+ writer.printf("mInitComplete: %s\n", mInitComplete);
+ writer.printf("OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: %s\n",
+ mOemServiceConnectionTimeoutMs);
+ writer.printf("OEM_CAR_SERVICE_READY_TIMEOUT_MS: %s\n", mOemServiceReadyTimeoutMs);
+ writer.printf("mComponentName: %s\n", mComponentName);
+ writer.printf("mCallbacks size: %d\n", mCallbacks.size());
+ // Dump OEM service stack
+ if (mIsOemServiceReady) {
+ writer.printf("OEM callstack\n");
+ int timeoutMs = 2000;
+ try {
+ writer.printf(mHelper.doBinderTimedCallWithTimeout(CALL_TAG,
+ () -> getOemService().getAllStackTraces(), timeoutMs));
+ } catch (TimeoutException e) {
+ writer.printf("Didn't received OEM stack within %d milliseconds.\n", timeoutMs);
+ }
+ }
+ // Dump helper
+ mHelper.dump(writer);
+ }
+ writer.decreaseIndent();
+ }
+
+ public String getOemServiceName() {
+ return mComponentName;
+ }
+
+ /**
+ * Gets OEM audio focus service.
+ */
+ @Nullable
+ public CarOemAudioFocusProxyService getCarOemAudioFocusService() {
+ if (!mIsFeatureEnabled) {
+ if (DBG) {
+ Slogf.d(TAG, "Oem Car Service is disabled, returning null for"
+ + " getCarOemAudioFocusService");
+ }
+ return null;
+ }
+
+ synchronized (mLock) {
+ if (mCarOemAudioFocusProxyService != null) {
+ return mCarOemAudioFocusProxyService;
+ }
+ }
+
+ waitForOemService();
+
+ // TODO(b/240615622): Domain owner to decide if retry or default or crash.
+ IOemCarAudioFocusService oemAudioFocusService = mHelper.doBinderTimedCallWithDefaultValue(
+ CALL_TAG, () -> getOemService().getOemAudioFocusService(),
+ /* defaultValue= */ null);
+
+ if (oemAudioFocusService == null) {
+ if (DBG) {
+ Slogf.d(TAG, "Oem Car Service doesn't implement AudioFocusService, returning null"
+ + " for getCarOemAudioFocusService");
+ }
+ return null;
+ }
+
+ CarOemAudioFocusProxyService carOemAudioFocusProxyService =
+ new CarOemAudioFocusProxyService(mHelper, oemAudioFocusService);
+ synchronized (mLock) {
+ if (mCarOemAudioFocusProxyService != null) {
+ return mCarOemAudioFocusProxyService;
+ }
+ mCarOemAudioFocusProxyService = carOemAudioFocusProxyService;
+ Slogf.i(TAG, "CarOemAudioFocusProxyService is ready.");
+ return mCarOemAudioFocusProxyService;
+ }
+ }
+
+ /**
+ * Should be called when CarService is ready for communication. It updates the OEM service that
+ * CarService is ready.
+ */
+ public void onCarServiceReady() {
+ waitForOemServiceConnected();
+ mHelper.doBinderOneWayCall(CALL_TAG, () -> {
+ try {
+ getOemService().onCarServiceReady(mOemCarServiceCallback);
+ } catch (RemoteException ex) {
+ Slogf.e(TAG, "Binder call received RemoteException, calling to crash CarService",
+ ex);
+ }
+ });
+ waitForOemServiceReady();
+ }
+
+ private void waitForOemServiceConnected() {
+ synchronized (mLock) {
+ if (!mInitComplete) {
+ // No CarOemService call should be made before or during init of ICarImpl.
+ throw new IllegalStateException(
+ "CarOemService should not be call before CarService initialization");
+ }
+
+ if (mIsOemServiceConnected) {
+ return;
+ }
+ waitForOemServiceConnectedLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void waitForOemServiceConnectedLocked() {
+ long startTime = SystemClock.elapsedRealtime();
+ long remainingTime = mOemServiceConnectionTimeoutMs;
+
+ while (!mIsOemServiceConnected && remainingTime > 0) {
+ try {
+ Slogf.i(TAG, "waiting to connect to OemService. wait time: %s", remainingTime);
+ mLock.wait(mOemServiceConnectionTimeoutMs);
+ remainingTime = mOemServiceConnectionTimeoutMs
+ - (SystemClock.elapsedRealtime() - startTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Slogf.w(TAG, "InterruptedException received. Reset interrupted status.", e);
+ }
+ }
+
+ if (!mIsOemServiceConnected) {
+ Slogf.e(TAG, "OEM Service is not connected within: %dms, calling to crash CarService",
+ mOemServiceConnectionTimeoutMs);
+ mHelper.crashCarService("OEM Service not connected");
+ }
+ }
+
+ private void waitForOemService() {
+ waitForOemServiceConnected();
+ waitForOemServiceReady();
+ }
+
+ private void waitForOemServiceReady() {
+ synchronized (mLock) {
+ if (mIsOemServiceReady) {
+ return;
+ }
+ }
+
+ try {
+ mOemServiceReadyLatch.await(mOemServiceReadyTimeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Slogf.i(TAG, "Exception while waiting for OEM Service to be ready.", e);
+ }
+
+ synchronized (mLock) {
+ if (!mIsOemServiceReady) {
+ Slogf.e(TAG, "OEM Service is not ready within: " + mOemServiceReadyTimeoutMs
+ + "ms, calling to crash CarService");
+ mHelper.crashCarService("OEM Service not ready");
+ }
+ }
+ Slogf.i(TAG, "OEM Service is ready.");
+ }
+
+ // Initialize all OEM related components.
+ private void initOemServiceComponents() {
+ // Initialize all Oem Service components
+ getCarOemAudioFocusService();
+
+ // Callback registered Car Service components for OEM service.
+ callCarServiceComponents();
+ }
+
+ private void callCarServiceComponents() {
+ synchronized (mLock) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onOemServiceReady();
+ }
+ }
+ }
+
+ /**
+ * Informs CarOemService that ICarImpl's init is complete.
+ */
+ // This would set mInitComplete, which is an additional check so that no car service component
+ // calls CarOemService during or before ICarImpl's init.
+ public void onInitComplete() {
+ if (!mIsFeatureEnabled) {
+ if (DBG) {
+ Slogf.d(TAG, "Oem Car Service is disabled, No-op for onInitComplete");
+ }
+ return;
+ }
+
+ synchronized (mLock) {
+ mInitComplete = true;
+ }
+ // inform OEM Service that CarService is ready for communication.
+ // It has to be posted on the different thread as this call is part of init process.
+ mHandler.post(() -> onCarServiceReady());
+ }
+
+ private IOemCarService getOemService() {
+ synchronized (mLock) {
+ return mOemCarService;
+ }
+ }
+
+ private class IOemCarServiceCallbackImpl extends IOemCarServiceCallback.Stub {
+ @Override
+ public void sendOemCarServiceReady() {
+ synchronized (mLock) {
+ mIsOemServiceReady = true;
+ }
+ mOemServiceReadyLatch.countDown();
+ int pid = Binder.getCallingPid();
+ Slogf.i(TAG, "OEM Car service is ready and running. Process ID of OEM Car Service is:"
+ + " %d", pid);
+ mHelper.updateOemPid(pid);
+ mHelper.updateOemStackCall(() -> getOemService().getAllStackTraces());
+ // Initialize other components on handler thread so that main thread is not
+ // blocked
+ mHandler.post(() -> initOemServiceComponents());
+ }
+ }
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyServiceCallback.java b/service/src/com/android/car/oem/CarOemProxyServiceCallback.java
new file mode 100644
index 0000000..277f64d
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyServiceCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+/**
+ * Callback for other CarService components when OEM service is ready.
+ *
+ * <p>Other CarService components are not expected to call OEM Service during init process. If they
+ * need to make call to OEM service as soon as OEM service is ready, then can register this
+ * callback to {link CarOemProxyService}. This callback will be called for all callback registered
+ * during init calls. The callback will be made only once after OEM service is connected.
+ */
+public interface CarOemProxyServiceCallback {
+ /**
+ * Called when OEM service is ready.
+ */
+ void onOemServiceReady();
+
+}
diff --git a/service/src/com/android/car/oem/CarOemProxyServiceHelper.java b/service/src/com/android/car/oem/CarOemProxyServiceHelper.java
new file mode 100644
index 0000000..9f194f0
--- /dev/null
+++ b/service/src/com/android/car/oem/CarOemProxyServiceHelper.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+import android.annotation.Nullable;
+import android.car.builtin.util.Slogf;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.car.CarLog;
+import com.android.car.R;
+import com.android.car.internal.util.IndentingPrintWriter;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+// TODO(b/239698894):Enhance logging to keep track of timeout calls, and dump last 10 timeout calls.
+
+/**
+ * This class does following:
+ * <ul>
+ * <li>Handles binder call to OEM Service and exposes multiple APIs to call OEM Service.
+ * <li>Handles OEM service crash.
+ * <li>Tracks circular call for OEM Service.
+ * </ul>
+ * <p>
+ * If there is more than {@link MAX_CIRCULAR_CALLS_PER_CALLER} circular calls per binder or more
+ * than {@link MAX_CIRCULAR_CALL_TOTAL} circular calls overall, Car Service and OEM service
+ * would be crashed.
+ */
+public final class CarOemProxyServiceHelper {
+
+ private static final String TAG = CarLog.tagFor(CarOemProxyServiceHelper.class);
+ private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
+
+ private static final int EXIT_FLAG = 10;
+
+ private static final int MAX_CIRCULAR_CALLS_PER_CALLER = 5;
+ private static final int MAX_CIRCULAR_CALL_TOTAL = 10;
+ private static final int MAX_THREAD_POOL_SIZE = 16;
+ private static final int MIN_THREAD_POOL_SIZE = 8;
+
+ private final Object mLock = new Object();
+
+ private final int mRegularCallTimeoutMs;
+ private final int mCrashCallTimeoutMs;
+ // Kept for dumping
+ private final int mThreadPoolSizeFromRRO;
+
+ // Thread pool size will be read from resource overlay. The default value is 8. The maximum
+ // and minimum thread pool size can be MAX_THREAD_POOL_SIZE and MIN_THREAD_POOL_SIZE
+ // respectively. If resource overlay value is more than MAX_THREAD_POOL_SIZE, then thread
+ // pool size will be MAX_THREAD_POOL_SIZE. If resource overlay value is less than
+ // MIN_THREAD_POOL_SIZE, then thread pool size will be MIN_THREAD_POOL_SIZE.
+ private final int mBinderDispatchThreadPoolSize;
+
+ /**
+ * This map would keep track of possible circular calls
+ * <p>
+ * Ideally there should not be any call from OEM service to Car Service but it may be required
+ * for some reason. In such situation, It is important that it doesn't create circular calls.
+ *
+ * For example:
+ * <ol>
+ * <li>CarService calling OEM Service
+ * <li>OEM Service calling car-lib
+ * <li>Car-lib calling CarService
+ * <li>CarService calling OEM Service again
+ * </ol>
+ * <p>
+ * This may create infinite loop. If something like this is detected, CarService and OEM Service
+ * would be crashed, and this map would keep track of such circular calls.
+ */
+ @GuardedBy("mLock")
+ private final ArrayMap<String, Integer> mCallerTracker = new ArrayMap<String, Integer>(2);
+
+ private final ExecutorService mThreadPool;
+ @GuardedBy("mLock")
+ private Callable<String> mOemStackTracer;
+ @GuardedBy("mLock")
+ private int mTotalCircularCallsInProcess;
+ @GuardedBy("mLock")
+ private int mOemCarServicePid;
+
+ public CarOemProxyServiceHelper(Context context) {
+ Resources res = context.getResources();
+ mRegularCallTimeoutMs = res
+ .getInteger(R.integer.config_oemCarService_regularCall_timeout_ms);
+ mCrashCallTimeoutMs = res
+ .getInteger(R.integer.config_oemCarService_crashCall_timeout_ms);
+ mThreadPoolSizeFromRRO = res
+ .getInteger(R.integer.config_oemCarService_thread_pool_size);
+ if (mThreadPoolSizeFromRRO > MAX_THREAD_POOL_SIZE) {
+ mBinderDispatchThreadPoolSize = MAX_THREAD_POOL_SIZE;
+ } else if (mThreadPoolSizeFromRRO < MIN_THREAD_POOL_SIZE) {
+ mBinderDispatchThreadPoolSize = MIN_THREAD_POOL_SIZE;
+ } else {
+ mBinderDispatchThreadPoolSize = mThreadPoolSizeFromRRO;
+ }
+
+ mThreadPool = Executors.newFixedThreadPool(mBinderDispatchThreadPoolSize);
+
+ Slogf.i(TAG, "RegularCallTimeoutMs: %d, CrashCallTimeoutMs: %d, ThreadPoolSizeFromRRO: %d,"
+ + " ThreadPoolSize: %d.", mRegularCallTimeoutMs,
+ mCrashCallTimeoutMs, mThreadPoolSizeFromRRO, mBinderDispatchThreadPoolSize);
+ }
+
+ /**
+ * Does timed call to the OEM service and returns default value if OEM service timed out or
+ * throws any other Exception.
+ *
+ * <p>Caller would not know if the call to OEM service timed out or returned a valid value which
+ * could be same as defaultValue. It is preferred way to call OEM service if the defaultValue is
+ * an acceptable result.
+ *
+ * @param <T> Type of the result.
+ * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+ * @param callable containing binder call.
+ * @param defaultValue to be returned if call timeout or any other exception is thrown.
+ *
+ * @return Result of the binder call. Result can be null.
+ */
+ @Nullable
+ public <T> T doBinderTimedCallWithDefaultValue(String callerTag, Callable<T> callable,
+ T defaultValue) {
+ if (DBG) {
+ Slogf.d(TAG, "Received doBinderTimedCallWithDefaultValue call for caller tag: %s.",
+ callerTag);
+ }
+ startTracking(callerTag);
+ try {
+ Future<T> result = mThreadPool.submit(callable);
+ try {
+ return result.get(mRegularCallTimeoutMs, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ Slogf.w(TAG, "Binder call threw an exception. Return default value %s for caller "
+ + "tag: %s", defaultValue, callerTag);
+ return defaultValue;
+ }
+ } finally {
+ stopTracking(callerTag);
+ }
+ }
+
+ /**
+ * Does timed call to the OEM service and throws timeout exception.
+ *
+ * <p>Throws timeout exception if OEM service times out. If OEM service throw any other
+ * exception, it is wrapped in Timeout exception.
+ *
+ * @param <T> Type of the result.
+ * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+ * @param callable containing binder call.
+ * @param timeoutMs in milliseconds.
+ *
+ * @return result of the binder call. Result can be null.
+ *
+ * @throws TimeoutException if call times out or throws any other exception.
+ */
+ @Nullable
+ public <T> T doBinderTimedCallWithTimeout(String callerTag, Callable<T> callable,
+ long timeoutMs) throws TimeoutException {
+ if (DBG) {
+ Slogf.d(TAG, "Received doBinderTimedCallWithTimeout call for caller tag: %s.",
+ callerTag);
+ }
+ startTracking(callerTag);
+ try {
+ Future<T> result = mThreadPool.submit(callable);
+ try {
+ return result.get(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException e) {
+ Slogf.w(TAG, "Binder call received Exception", e);
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ // Throw timeout exception even for other exception as caller knows how to handle
+ // timeout exception in this case.
+ TimeoutException exception = new TimeoutException();
+ exception.initCause(e);
+ throw exception;
+ }
+ } finally {
+ stopTracking(callerTag);
+ }
+ }
+
+ /**
+ * Does timed call to OEM service with two different timeouts.
+ *
+ * <p>If OEM service returns before the {@code defaultTimeoutMs}, it would return OEM response.
+ * After {@code defaultTimeoutMs}, call will return {@link Optional#empty()} and queue a tracker
+ * for OEM service response asynchronously. Tracker would wait for {@code mCrashCallTimeoutMs}
+ * for OEM service to response. If OEM service respond before {code mCrashCallTimeoutMs},
+ * callback {@code CallbackForDelayedResult} will be used to post the OEM results on the
+ * original caller. If OEM service doesn't respond within {code mCrashCallTimeoutMs}, CarService
+ * and OEM service both will be crashed.
+ *
+ * <p>This call should be used if it is okay to quickly check for results from OEM Service, and
+ * it is possible to incorporate results from OEM service if delivered late.
+ *
+ * <p>If the binder to OEM service throw any exception during short timeout, it would be ignored
+ * and {@link Optional#empty()} is returned. If the binder to OEM service throw timeout
+ * exception after the longer timeout, it would rash the CarService and OEM Service. If the
+ * binder to OEM service throw any other exception during longer timeout, it would be ignored
+ * and {@link Optional#empty()} is returned.
+ *
+ * @param <T> Type of the result.
+ * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+ * @param callable containing binder call.
+ * @param defaultTimeoutMs in milliseconds.
+ * @param callback for the delayed results. Callback waits for {@code mCrashCallTimeoutMs}.
+ *
+ * @return Optional carrying result of the binder call. Optional can be empty.
+ */
+ public <T> Optional<T> doBinderCallWithDefaultValueAndDelayedWaitAndCrash(String callerTag,
+ Callable<T> callable, long defaultTimeoutMs,
+ CallbackForDelayedResult<T> callback) {
+ if (DBG) {
+ Slogf.d(TAG, "Received doBinderCallWithDefaultValueAndDelayedWaitAndCrash call for"
+ + " caller tag: %s.", callerTag);
+ }
+ startTracking(callerTag);
+ try {
+ Future<T> result = mThreadPool.submit(callable);
+ try {
+ return Optional.ofNullable(result.get(defaultTimeoutMs, TimeUnit.MILLISECONDS));
+ } catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ Slogf.e(TAG, "Binder call received Exception", e);
+ }
+
+ // Queue for long wait time check
+ mThreadPool.execute(() -> {
+ startTracking(callerTag);
+ try {
+ callback.onDelayedResults(
+ Optional.ofNullable(
+ result.get(mCrashCallTimeoutMs, TimeUnit.MILLISECONDS)));
+ } catch (TimeoutException e) {
+ Slogf.e(TAG, "Binder call received TimeoutException", e);
+ crashCarService("TimeoutException");
+ } catch (InterruptedException | ExecutionException e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ Slogf.e(TAG, "Binder call received Eexception", e);
+ callback.onDelayedResults(Optional.empty());
+ } finally {
+ stopTracking(callerTag);
+ }
+ });
+ } finally {
+ stopTracking(callerTag);
+ }
+
+ return Optional.empty();
+ }
+
+ /**
+ * Callback for getting OEM results after default timeout.
+ *
+ * @param <T> Type of the result.
+ */
+ public interface CallbackForDelayedResult<T> {
+ /**
+ * Invoked when OEM results are received after default timeout.
+ *
+ * @param result received from OEM service
+ */
+ void onDelayedResults(Optional<T> result);
+ }
+
+ private void stopTracking(String callerTag) {
+ synchronized (mLock) {
+ if (Binder.getCallingPid() != mOemCarServicePid) return;
+ }
+ // update tracker
+ synchronized (mLock) {
+ int currentCircularCallForTag = mCallerTracker.getOrDefault(callerTag, 0);
+ if (currentCircularCallForTag <= 0 || mTotalCircularCallsInProcess <= 0) {
+ Slogf.wtf(TAG, "Current Circular Calls for %s is %d which is unexpected.",
+ callerTag, currentCircularCallForTag);
+ }
+ mCallerTracker.put(callerTag, currentCircularCallForTag - 1);
+ mTotalCircularCallsInProcess = mTotalCircularCallsInProcess - 1;
+ }
+ }
+
+ private void startTracking(String callerTag) {
+ synchronized (mLock) {
+ if (Binder.getCallingPid() != mOemCarServicePid) return;
+ }
+
+ int currentCircularCallForTag;
+ int totalCircularCallsInProcess;
+
+ synchronized (mLock) {
+ currentCircularCallForTag = mCallerTracker.getOrDefault(callerTag, 0);
+ totalCircularCallsInProcess = mTotalCircularCallsInProcess;
+ }
+
+ Slogf.w(TAG, "Possible circular call for %s. Current circular calls are %d."
+ + " Total circular calls are %d.", callerTag, currentCircularCallForTag,
+ totalCircularCallsInProcess);
+
+ if (currentCircularCallForTag + 1 > MAX_CIRCULAR_CALLS_PER_CALLER) {
+ Slogf.e(TAG, "Current Circular Calls for %s is %d which is more than the limit %d."
+ + " Calling to crash CarService", callerTag, (currentCircularCallForTag + 1),
+ MAX_CIRCULAR_CALLS_PER_CALLER);
+ crashCarService("Max Circular call for " + callerTag);
+ }
+
+ if (totalCircularCallsInProcess + 1 > MAX_CIRCULAR_CALL_TOTAL) {
+ Slogf.e(TAG, "Total Circular Calls is %d which is more than the limit %d."
+ + " Calling to crash CarService", (totalCircularCallsInProcess + 1),
+ MAX_CIRCULAR_CALL_TOTAL);
+ crashCarService("Max Circular calls overall");
+ }
+
+ // update tracker
+ synchronized (mLock) {
+ mCallerTracker.put(callerTag, mCallerTracker.getOrDefault(callerTag, 0) + 1);
+ mTotalCircularCallsInProcess = mTotalCircularCallsInProcess + 1;
+ }
+ }
+
+ /**
+ * Does timed call to the OEM service and crashes the OEM and Car Service if call is not served
+ * within time.
+ *
+ * <p>If OEM service throw TimeoutException, it would crash the CarService and OEM service. If
+ * OemService throws any other exception, {@link Optional#empty()} is returned.
+ *
+ * @param <T> Type of the result.
+ * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+ * @param callable containing binder call.
+ *
+ * @return Optional carrying result of the binder call. Optional can be empty.
+ */
+ public <T> Optional<T> doBinderCallWithTimeoutCrash(String callerTag, Callable<T> callable) {
+ if (DBG) {
+ Slogf.d(TAG, "Received doBinderCallWithTimeoutCrash call for caller tag: %s.",
+ callerTag);
+ }
+ startTracking(callerTag);
+ try {
+ Future<T> result = mThreadPool.submit(callable);
+ try {
+ return Optional.ofNullable(result.get(mCrashCallTimeoutMs, TimeUnit.MILLISECONDS));
+ } catch (TimeoutException e) {
+ Slogf.e(TAG, "Binder call received Exception", e);
+ crashCarService("TimeoutException");
+ } catch (InterruptedException | ExecutionException e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ Slogf.e(TAG, "Binder call received Exception", e);
+ return Optional.empty();
+ }
+ } finally {
+ stopTracking(callerTag);
+ }
+
+ throw new AssertionError("Should not return from crashCarService");
+ }
+
+ /**
+ * Does one way call to OEM Service. Runnable will be queued to threadpool and not waited for
+ * completion.
+ *
+ * <p>It is recommended to use callable with some result if waiting for call to complete is
+ * required.
+ *
+ * @param callerTag is tag from the caller. Used for tracking circular calls per binder.
+ * @param runnable containing binder call
+ */
+ public void doBinderOneWayCall(String callerTag, Runnable runnable) {
+ if (DBG) {
+ Slogf.d(TAG, "Received doBinderOneWayCall call for caller tag: %s.", callerTag);
+ }
+
+ mThreadPool.execute(() -> {
+ startTracking(callerTag);
+ try {
+ Future<?> result = mThreadPool.submit(runnable);
+ try {
+ result.get(mRegularCallTimeoutMs, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt(); // Restore the interrupted status
+ }
+ Slogf.e(TAG, "Exception while running a runnable for caller tag: " + callerTag,
+ e);
+ }
+ } finally {
+ stopTracking(callerTag);
+ }
+ });
+ }
+
+ /**
+ * Crashes CarService and OEM Service.
+ */
+ public void crashCarService(String reason) {
+ Slogf.e(TAG, "****Crashing CarService and OEM service because %s****", reason);
+ Slogf.e(TAG, "Car Service stack-");
+ Slogf.e(TAG, Log.getStackTraceString(new Exception()));
+
+ Callable<String> oemStackTracer = null;
+ synchronized (mLock) {
+ oemStackTracer = mOemStackTracer;
+ }
+
+ if (oemStackTracer != null) {
+ Slogf.e(TAG, "OEM Service stack-");
+ int timeoutMs = 2000;
+ try {
+ String stack = doBinderTimedCallWithTimeout(TAG, oemStackTracer, timeoutMs);
+ Slogf.e(TAG, stack);
+ } catch (TimeoutException e) {
+ Slogf.e(TAG, "Didn't received OEM stack within %d milliseconds.\n", timeoutMs);
+ }
+ }
+
+ int carServicePid = Process.myPid();
+ int oemCarServicePid;
+ synchronized (mLock) {
+ oemCarServicePid = mOemCarServicePid;
+ }
+
+ if (oemCarServicePid != 0) {
+ Slogf.e(TAG, "Killing OEM service process with PID %d.", oemCarServicePid);
+ Process.killProcess(oemCarServicePid);
+ }
+ Slogf.e(TAG, "Killing Car service process with PID %d.", carServicePid);
+ Process.killProcess(carServicePid);
+ System.exit(EXIT_FLAG);
+ }
+
+ /**
+ * Updates PID of the OEM process.
+ */
+ public void updateOemPid(int pid) {
+ synchronized (mLock) {
+ mOemCarServicePid = pid;
+ }
+ }
+
+ /**
+ * Dumps
+ */
+ public void dump(IndentingPrintWriter writer) {
+ writer.println("***CarOemProxyServiceHelper dump***");
+ writer.increaseIndent();
+ synchronized (mLock) {
+ writer.printf("mOemCarServicePid: %d\n", mOemCarServicePid);
+ writer.printf("mCallerTracker.size: %d\n", mCallerTracker.size());
+ if (mCallerTracker.size() > 0) {
+ writer.increaseIndent();
+ for (int i = 0; i < mCallerTracker.size(); i++) {
+ writer.printf("mCallerTracker entry: %d, CallerTag: %s, CircularCalls: %d\n", i,
+ mCallerTracker.keyAt(i), mCallerTracker.valueAt(i));
+ }
+ writer.decreaseIndent();
+ }
+ writer.printf("mRegularCallTimeoutMs: %d\n", mRegularCallTimeoutMs);
+ writer.printf("mCrashCallTimeoutMs: %d\n", mCrashCallTimeoutMs);
+ writer.printf("mBinderDispatchThreadPoolSize: %d\n", mBinderDispatchThreadPoolSize);
+ writer.printf("ThreadPoolSizeFromRRO: %d\n", mThreadPoolSizeFromRRO);
+ }
+ writer.decreaseIndent();
+ }
+
+ /**
+ * Updates call for getting OEM stack trace.
+ */
+ public void updateOemStackCall(Callable<String> oemStackTracer) {
+ synchronized (mLock) {
+ mOemStackTracer = oemStackTracer;
+ }
+ }
+}
diff --git a/service/src/com/android/car/power/CarPowerManagementService.java b/service/src/com/android/car/power/CarPowerManagementService.java
index 8caf3ca..8966abb 100644
--- a/service/src/com/android/car/power/CarPowerManagementService.java
+++ b/service/src/com/android/car/power/CarPowerManagementService.java
@@ -569,6 +569,14 @@
// TODO(b/177478420): Restore Wifi, Audio, Location, and Bluetooth, if they are artificially
// modified for S2R.
mSilentModeHandler.querySilentModeHwState();
+
+ applyDefaultPowerPolicyForState(CarPowerManager.STATE_WAIT_FOR_VHAL,
+ PolicyReader.POWER_POLICY_ID_INITIAL_ON);
+
+ if (!mSilentModeHandler.isSilentMode()) {
+ cancelPreemptivePowerPolicy();
+ }
+
sendPowerManagerEvent(carPowerStateListenerState, INVALID_TIMEOUT);
// Inspect CarPowerStateListenerState to decide which message to send via VHAL
switch (carPowerStateListenerState) {
@@ -1977,23 +1985,25 @@
}
// We failed to suspend. Block the thread briefly and try again.
synchronized (mLock) {
- if (mPendingPowerStates.isEmpty()) {
- Slogf.w(TAG, "Failed to Suspend; will retry after %dms", retryIntervalMs);
- try {
- mLock.wait(retryIntervalMs);
- } catch (InterruptedException ignored) {
- Thread.currentThread().interrupt();
- }
- totalWaitDurationMs += retryIntervalMs;
- retryIntervalMs = Math.min(retryIntervalMs * 2, MAX_RETRY_INTERVAL_MS);
- } else {
+ if (!mPendingPowerStates.isEmpty()) {
// Check for a new power state now, before going around the loop again.
CpmsState state = mPendingPowerStates.peekFirst();
if (state != null && needPowerStateChangeLocked(state)) {
- Slogf.i(TAG, "Terminating the attempt to %s", suspendTarget);
+ Slogf.i(TAG, "Terminating the attempt to suspend target = %s,"
+ + " currentState = %s, pendingState = %s", suspendTarget,
+ mCurrentState.stateToString(), state.stateToString());
return false;
}
}
+
+ Slogf.w(TAG, "Failed to Suspend; will retry after %dms", retryIntervalMs);
+ try {
+ mLock.wait(retryIntervalMs);
+ } catch (InterruptedException ignored) {
+ Thread.currentThread().interrupt();
+ }
+ totalWaitDurationMs += retryIntervalMs;
+ retryIntervalMs = Math.min(retryIntervalMs * 2, MAX_RETRY_INTERVAL_MS);
}
}
// Too many failures trying to suspend. Shut down.
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index 9a2e9f3..2fb792c 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -36,6 +36,7 @@
import android.hardware.automotive.vehicle.VehicleApPowerStateReport;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
@@ -98,6 +99,7 @@
private static final String TAG_OTHER_COMPONENTS = "otherComponents";
private static final String TAG_COMPONENT = "component";
private static final String TAG_SYSTEM_POLICY_OVERRIDES = "systemPolicyOverrides";
+ private static final String ATTR_DEFAULT_POLICY_GROUP = "defaultPolicyGroup";
private static final String ATTR_VERSION = "version";
private static final String ATTR_ID = "id";
private static final String ATTR_STATE = "state";
@@ -155,6 +157,7 @@
private ArrayMap<String, CarPowerPolicy> mRegisteredPowerPolicies;
private ArrayMap<String, SparseArray<String>> mPolicyGroups;
private ArrayMap<String, CarPowerPolicy> mPreemptivePowerPolicies;
+ private String mDefaultPolicyGroupId;
/**
* Gets {@code CarPowerPolicy} corresponding to the given policy ID.
@@ -170,7 +173,8 @@
*/
@Nullable
CarPowerPolicy getDefaultPowerPolicyForState(String groupId, int state) {
- SparseArray<String> group = mPolicyGroups.get(groupId);
+ SparseArray<String> group = mPolicyGroups.get(
+ (groupId == null || groupId.isEmpty()) ? mDefaultPolicyGroupId : groupId);
if (group == null) {
return null;
}
@@ -200,6 +204,16 @@
return mPreemptivePowerPolicies.containsKey(policyId);
}
+ /**
+ * Gets default power policy group ID.
+ *
+ * @return {@code String} containing power policy group ID or {@code null} if it is not defined
+ */
+ @Nullable
+ String getDefaultPowerPolicyGroup() {
+ return mDefaultPolicyGroupId;
+ }
+
void init() {
initPolicies();
readPowerPolicyConfiguration();
@@ -346,6 +360,7 @@
ArrayMap<String, CarPowerPolicy> registeredPolicies = new ArrayMap<>();
ArrayMap<String, SparseArray<String>> policyGroups = new ArrayMap<>();
CarPowerPolicy systemPolicyOverride = null;
+ String defaultGroupPolicyId = null;
int type;
while ((type = parser.next()) != END_DOCUMENT && type != END_TAG) {
@@ -355,6 +370,8 @@
registeredPolicies = parsePolicies(parser, true);
break;
case TAG_POLICY_GROUPS:
+ defaultGroupPolicyId = parser.getAttributeValue(NAMESPACE,
+ ATTR_DEFAULT_POLICY_GROUP);
policyGroups = parsePolicyGroups(parser);
break;
case TAG_SYSTEM_POLICY_OVERRIDES:
@@ -365,8 +382,9 @@
+ TAG_POWER_POLICY);
}
}
- validatePolicyGroups(policyGroups, registeredPolicies);
+ validatePolicyGroups(policyGroups, registeredPolicies, defaultGroupPolicyId);
+ mDefaultPolicyGroupId = defaultGroupPolicyId;
mRegisteredPowerPolicies = registeredPolicies;
registerBasicPowerPolicies();
mPolicyGroups = policyGroups;
@@ -576,7 +594,8 @@
}
private void validatePolicyGroups(ArrayMap<String, SparseArray<String>> policyGroups,
- ArrayMap<String, CarPowerPolicy> registeredPolicies) throws PolicyXmlException {
+ ArrayMap<String, CarPowerPolicy> registeredPolicies, String defaultGroupPolicyId)
+ throws PolicyXmlException {
for (Map.Entry<String, SparseArray<String>> entry : policyGroups.entrySet()) {
SparseArray<String> group = entry.getValue();
for (int i = 0; i < group.size(); i++) {
@@ -587,6 +606,16 @@
}
}
}
+
+ if ((defaultGroupPolicyId == null || defaultGroupPolicyId.isEmpty())
+ && !policyGroups.isEmpty()) {
+ Log.w(TAG, "No defaultGroupPolicyId is defined");
+ }
+
+ if (defaultGroupPolicyId != null && !policyGroups.containsKey(defaultGroupPolicyId)) {
+ throw new PolicyXmlException(
+ "defaultGroupPolicyId is defined, but group with this ID doesn't exist ");
+ }
}
private void reconstructSystemPowerPolicy(@Nullable CarPowerPolicy policyOverride) {
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index 74e2bbd..91e9af5 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -46,10 +46,12 @@
import com.android.car.CarLog;
import com.android.car.CarServiceUtils;
+import com.android.car.internal.LargeParcelable;
import com.android.car.telemetry.CarTelemetryService;
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.publisher.AbstractPublisher;
import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
import com.android.car.telemetry.util.IoUtils;
@@ -83,7 +85,6 @@
/** Maximum wait time for a script to finish. */
private static final long MAX_SCRIPT_EXECUTION_TIME_MILLIS = 30_000L; // 30 seconds
- // TODO(b/216134347): Find a better way to find the package.
private static final String[] SCRIPT_EXECUTOR_PACKAGE_CANDIDATES =
{"com.android.car.scriptexecutor", "com.google.android.car.scriptexecutor"};
private static final String SCRIPT_EXECUTOR_CLASS =
@@ -487,6 +488,14 @@
mCurrentMetricsConfigName);
}
invokeScriptForLargeInput(task);
+ } else if (task.isBundleList()) {
+ if (DEBUG) {
+ Slogf.d(CarLog.TAG_TELEMETRY,
+ "Running with bundle list func %s of %s in ScriptExecutor.",
+ task.getHandlerName(),
+ mCurrentMetricsConfigName);
+ }
+ invokeScriptForBundleList(task);
} else {
if (DEBUG) {
Slogf.d(CarLog.TAG_TELEMETRY, "Running func %s of %s in ScriptExecutor.",
@@ -549,6 +558,30 @@
}
}
+ /**
+ * Sends bundle list with LargeParcelable mechanism.
+ *
+ * @param task containing all the necessary parameters for ScriptExecutor API.
+ * @throws RemoteException if ScriptExecutor failed.
+ */
+ private void invokeScriptForBundleList(@NonNull ScriptExecutionTask task)
+ throws RemoteException {
+ BundleList bl = new BundleList();
+ bl.bundles = task.getBundleList();
+ bl = (BundleList) LargeParcelable.toLargeParcelable(
+ bl, () -> {
+ BundleList bundleList = new BundleList();
+ bundleList.bundles = new ArrayList<>();
+ return bundleList;
+ });
+ mScriptExecutor.invokeScriptForBundleList(
+ task.getMetricsConfig().getScript(),
+ task.getHandlerName(),
+ bl,
+ mResultStore.getInterimResult(mCurrentMetricsConfigName),
+ mScriptExecutorListener);
+ }
+
private TelemetryError buildTelemetryError(
@NonNull TelemetryError.ErrorType errorType,
@NonNull String message,
diff --git a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
index ab77318..a560bcc 100644
--- a/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
+++ b/service/src/com/android/car/telemetry/databroker/DataSubscriber.java
@@ -21,6 +21,7 @@
import android.os.PersistableBundle;
import android.os.SystemClock;
+import java.util.List;
import java.util.Objects;
/**
@@ -88,6 +89,20 @@
/**
* Creates a {@link ScriptExecutionTask} and pushes it to the priority queue where the task
+ * will be pending execution.
+ *
+ * @param bundleList The published bundle list data.
+ * @return The number of tasks that are pending execution that are produced by the calling
+ * publisher.
+ */
+ public int push(@NonNull List<PersistableBundle> bundleList) {
+ ScriptExecutionTask task = new ScriptExecutionTask(
+ this, bundleList, SystemClock.elapsedRealtime(), getPublisherType());
+ return mDataBroker.addTaskToQueue(task);
+ }
+
+ /**
+ * Creates a {@link ScriptExecutionTask} and pushes it to the priority queue where the task
* will be pending execution. Defaults isLargeData flag to false.
*
* @param data The published data.
diff --git a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
index 796792c..26881c9 100644
--- a/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
+++ b/service/src/com/android/car/telemetry/databroker/ScriptExecutionTask.java
@@ -17,9 +17,12 @@
package com.android.car.telemetry.databroker;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.car.telemetry.TelemetryProto;
import android.os.PersistableBundle;
+import java.util.List;
+
/**
* A wrapper class containing all the necessary information to invoke the ScriptExecutor API. It
* is enqueued into the priority queue where it pends execution by {@link DataBroker}.
@@ -31,8 +34,10 @@
private final int mPublisherType;
private final long mTimestampMillis;
private final DataSubscriber mSubscriber;
- private final PersistableBundle mData;
- private final boolean mIsLargeData;
+
+ private PersistableBundle mData = null;
+ private List<PersistableBundle> mBundleList = null;
+ private boolean mIsLargeData = false;
ScriptExecutionTask(
@NonNull DataSubscriber subscriber,
@@ -47,6 +52,17 @@
mPublisherType = publisherType;
}
+ ScriptExecutionTask(
+ @NonNull DataSubscriber subscriber,
+ @NonNull List<PersistableBundle> bundleList,
+ long elapsedRealtimeMillis,
+ int publisherType) {
+ mTimestampMillis = elapsedRealtimeMillis;
+ mSubscriber = subscriber;
+ mBundleList = bundleList;
+ mPublisherType = publisherType;
+ }
+
public int getPublisherType() {
return mPublisherType;
}
@@ -74,11 +90,17 @@
}
/** Returns the data being sent to the subscriber. */
- @NonNull
+ @Nullable
public PersistableBundle getData() {
return mData;
}
+ /** Returns the bundle list data being sent to subscriber. */
+ @Nullable
+ public List<PersistableBundle> getBundleList() {
+ return mBundleList;
+ }
+
/**
* Indicates whether the task is associated with MetricsConfig specified by its name.
*/
@@ -93,6 +115,13 @@
return mIsLargeData;
}
+ /**
+ * Returns if the data is a list of bundles.
+ */
+ public boolean isBundleList() {
+ return mBundleList != null;
+ }
+
/** Determines if the task is eligible to bypass script executor. */
public boolean bypassScriptExecutor() {
return getHandlerName().isEmpty();
diff --git a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
index f161cd5..2bc7a8c 100644
--- a/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/ConnectivityPublisher.java
@@ -173,7 +173,11 @@
}
try {
for (QueryParam param : mSubscribers.keySet()) {
- mTransportPreviousNetstats.put(param, getSummaryForAllUid(param));
+ RefinedStats summary = getSummaryForAllUid(param);
+ if (summary == null) {
+ continue;
+ }
+ mTransportPreviousNetstats.put(param, summary);
}
} catch (RemoteException e) {
// Can't do much if the NetworkStatsService is not available. Next netstats pull
@@ -204,7 +208,7 @@
continue;
}
PersistableBundle data = previousSessionData.getPersistableBundle(key);
- if (!data.containsKey(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)) {
+ if (!data.containsKey(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)) {
Slogf.e(CarLog.TAG_TELEMETRY,
"Session annotations is unexpectedly missing. Skipping this batch.");
continue;
@@ -233,13 +237,17 @@
RefinedStats current;
try {
current = getSummaryForAllUid(param);
- } catch (RemoteException | NullPointerException e) {
+ } catch (RemoteException e) {
// If the NetworkStatsService is not available, it retries in the next pull.
Slogf.w(CarLog.TAG_TELEMETRY, e);
mTraceLog.traceEnd();
return null;
}
+ if (current == null) {
+ mTraceLog.traceEnd();
+ return null;
+ }
// By subtracting, it calculates network usage since the last pull.
RefinedStats diff = RefinedStats.subtract(current, previous);
@@ -260,7 +268,7 @@
*
* <p>TODO(b/218529196): run this method on a separate thread for better performance.
*/
- @NonNull
+ @Nullable
private RefinedStats getSummaryForAllUid(@NonNull QueryParam param) throws RemoteException {
if (DEBUG) {
Slogf.d(CarLog.TAG_TELEMETRY, "getSummaryForAllUid " + param);
@@ -273,12 +281,22 @@
- elapsedMillisSinceBoot
- NETSTATS_UID_DEFAULT_BUCKET_DURATION_MILLIS;
- NetworkStatsWrapper nonTaggedStats =
- mNetworkStatsManager.querySummary(
- param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
- NetworkStatsWrapper taggedStats =
- mNetworkStatsManager.queryTaggedSummary(
- param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+ NetworkStatsWrapper nonTaggedStats;
+ NetworkStatsWrapper taggedStats;
+ // querySummary and queryTaggedSummary may throw NPE propagated from NetworkStatsService
+ // when its NetworkStatsRecorder failed to initialize and
+ // NetworkStatsRecorder.getOrLoadCompleteLocked() is called.
+ try {
+ nonTaggedStats =
+ mNetworkStatsManager.querySummary(
+ param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+ taggedStats =
+ mNetworkStatsManager.queryTaggedSummary(
+ param.buildNetworkTemplate(), startMillis, currentTimeInMillis);
+ } catch (NullPointerException e) {
+ Slogf.w(CarLog.TAG_TELEMETRY, e);
+ return null;
+ }
RefinedStats result = new RefinedStats(startMillis, currentTimeInMillis);
result.addNetworkStats(nonTaggedStats);
diff --git a/service/src/com/android/car/telemetry/publisher/Constants.java b/service/src/com/android/car/telemetry/publisher/Constants.java
index edc4b3f..53db170 100644
--- a/service/src/com/android/car/telemetry/publisher/Constants.java
+++ b/service/src/com/android/car/telemetry/publisher/Constants.java
@@ -30,8 +30,56 @@
* populated.
*/
public final class Constants {
- public static final String CAR_TELEMETRYD_BUNDLE_KEY_ID = "id";
- public static final String CAR_TELEMETRYD_BUNDLE_KEY_CONTENT = "content";
+ // Session Annotations
+ public static final String ANNOTATION_BUNDLE_KEY_SESSION_ID = "session.sessionId";
+ public static final String ANNOTATION_BUNDLE_KEY_SESSION_STATE = "session.sessionState";
+ public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS =
+ "session.createdAtSinceBootMillis";
+ public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS = "session.createdAtMillis";
+ public static final String ANNOTATION_BUNDLE_KEY_BOOT_REASON = "session.bootReason";
+
+ // StatsPublisher
+ public static final String STATS_BUNDLE_KEY_PREFIX = "stats.";
+ public static final String STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP = "stats.elapsed_timestamp_nanos";
+
+ // CarTelemetrydPublisher
+ public static final String CAR_TELEMETRYD_BUNDLE_KEY_ID = "ct.id";
+ public static final String CAR_TELEMETRYD_BUNDLE_KEY_CONTENT = "ct.content";
+
+ // MemoryPublisher
+ public static final String MEMORY_BUNDLE_KEY_PREFIX = "mem.";
+ public static final String MEMORY_BUNDLE_KEY_MEMINFO = "mem.meminfo";
+ public static final String MEMORY_BUNDLE_KEY_TIMESTAMP = "mem.timestamp_millis";
+ public static final String MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS = "mem.total_swappable_pss";
+ public static final String MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY = "mem.total_private_dirty";
+ public static final String MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY = "mem.total_shared_dirty";
+ public static final String MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN = "mem.total_private_clean";
+ public static final String MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN = "mem.total_shared_clean";
+
+ // ConnectivityPublisher
+ public static final String CONNECTIVITY_BUNDLE_KEY_START_MILLIS = "conn.startMillis";
+ public static final String CONNECTIVITY_BUNDLE_KEY_END_MILLIS = "conn.endMillis";
+ public static final String CONNECTIVITY_BUNDLE_KEY_SIZE = "conn.size";
+ public static final String CONNECTIVITY_BUNDLE_KEY_UID = "conn.uid";
+ public static final String CONNECTIVITY_BUNDLE_KEY_PACKAGES = "conn.packages";
+ public static final String CONNECTIVITY_BUNDLE_KEY_TAG = "conn.tag";
+ public static final String CONNECTIVITY_BUNDLE_KEY_RX_BYTES = "conn.rxBytes";
+ public static final String CONNECTIVITY_BUNDLE_KEY_TX_BYTES = "conn.txBytes";
+
+ // VehiclePropertyPublisher
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_TIMESTAMP = "vp.timestamp";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_PROP_ID = "vp.propertyId";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_AREA_ID = "vp.areaId";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_STATUS = "vp.status";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_STRING = "vp.stringVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN = "vp.boolVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_INT = "vp.intVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY = "vp.intArrayVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_LONG = "vp.longVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY = "vp.longArrayVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT = "vp.floatVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY = "vp.floatArrayVal";
+ public static final String VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY = "vp.byteArrayVal";
private Constants() {
}
diff --git a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
index 5c53fd1..7d30fe0 100644
--- a/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/MemoryPublisher.java
@@ -17,14 +17,20 @@
package com.android.car.telemetry.publisher;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.car.builtin.os.TraceHelper;
+import android.car.builtin.util.Slogf;
import android.car.builtin.util.TimingsTraceLog;
import android.car.telemetry.TelemetryProto;
import android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
+import android.content.Context;
+import android.os.Debug;
import android.os.Handler;
import android.os.PersistableBundle;
+import android.provider.Settings;
import com.android.car.CarLog;
+import com.android.car.telemetry.CarTelemetryService;
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.databroker.DataSubscriber;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
@@ -36,7 +42,12 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Publisher implementation for {@link TelemetryProto.MemoryPublisher}.
@@ -48,25 +59,45 @@
*
* <p>Failure to read from /proc/meminfo will cause a {@link TelemetryProto.TelemetryError} to be
* returned to the client.
+ *
+ * <p>The published data format is:
+ * <code>
+ * - mem.timestamp_millis : long
+ * - mem.meminfo : string (device meminfo)
+ * - package_name:uid:process_name : PersistableBundle (parsed from Debug.MemInfo, listed below)
+ * - mem.summary.total-pss : int
+ * - mem.summary.java-heap : int
+ * - mem.summary.native-heap : int
+ * - mem.summary.stack : int
+ * - mem.summary.system : int
+ * - mem.summary.code : int
+ * - mem.summary.graphics : int
+ * - mem.summary.private-other : int
+ * - mem.summary.total-swap : int
+ * - mem.total_shared_clean : int
+ * - mem.total_shared_dirty : int
+ * - mem.total_private_clean : int
+ * - mem.total_private_dirty : int
+ * - mem.total_swappable_pss : int
+ * </code>
*/
public class MemoryPublisher extends AbstractPublisher {
private static final int MILLIS_IN_SECOND = 1000;
+ private static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
@VisibleForTesting
static final int THROTTLE_MILLIS = 60 * MILLIS_IN_SECOND;
@VisibleForTesting
static final String BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH = "num_snapshots_left";
@VisibleForTesting
static final String BUNDLE_KEY_COLLECT_INDEFINITELY = "collect_indefinitely";
- @VisibleForTesting
- static final String DATA_BUNDLE_KEY_MEMINFO = "meminfo";
- @VisibleForTesting
- static final String DATA_BUNDLE_KEY_TIMESTAMP = "timestamp";
- private final Runnable mReadMeminfoRunnable = this::readMemInfo;
+ private final ActivityManager mActivityManager;
+ private final Context mContext;
private final Handler mTelemetryHandler;
private final Path mMeminfoPath;
private final ResultStore mResultStore;
+ private final Runnable mReadMeminfoRunnable = this::readMemInfo;
private final TimingsTraceLog mTraceLog;
private MemorySubscriberWrapper mSubscriber;
@@ -74,25 +105,29 @@
private SessionAnnotation mSessionAnnotation;
MemoryPublisher(
+ @NonNull Context context,
@NonNull PublisherListener listener,
@NonNull Handler telemetryHandler,
@NonNull ResultStore resultStore,
@NonNull SessionController sessionController) {
- this(listener, telemetryHandler, resultStore, sessionController,
+ this(context, listener, telemetryHandler, resultStore, sessionController,
Paths.get("/proc/meminfo"));
}
@VisibleForTesting
MemoryPublisher(
+ @NonNull Context context,
@NonNull PublisherListener listener,
@NonNull Handler telemetryHandler,
@NonNull ResultStore resultStore,
@NonNull SessionController sessionController,
@NonNull Path meminfoPath) {
super(listener);
+ mContext = context;
mTelemetryHandler = telemetryHandler;
mResultStore = resultStore;
mMeminfoPath = meminfoPath;
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
mPublisherState = mResultStore.getPublisherData(
MemoryPublisher.class.getSimpleName(), false);
mTraceLog = new TimingsTraceLog(
@@ -176,10 +211,10 @@
resetPublisher();
return;
}
- mTraceLog.traceBegin("Reading /proc/meminfo and publishing");
+ mTraceLog.traceBegin("Reading meminfo and publishing");
// Read timestamp and meminfo and create published data
PersistableBundle data = new PersistableBundle();
- data.putLong(DATA_BUNDLE_KEY_TIMESTAMP, System.currentTimeMillis());
+ data.putLong(Constants.MEMORY_BUNDLE_KEY_TIMESTAMP, System.currentTimeMillis());
String meminfo;
try {
meminfo = new String(Files.readAllBytes(mMeminfoPath));
@@ -190,7 +225,12 @@
mTraceLog.traceEnd();
return;
}
- data.putString(DATA_BUNDLE_KEY_MEMINFO, meminfo);
+ data.putString(Constants.MEMORY_BUNDLE_KEY_MEMINFO, meminfo);
+
+ if (!mSubscriber.mPackageNames.isEmpty()) {
+ readProcessMeminfo(data);
+ }
+
// add sessions info to published data if available
if (mSessionAnnotation != null) {
mSessionAnnotation.addAnnotationsToBundle(data);
@@ -213,13 +253,91 @@
// if there are too many pending tasks from this publisher, throttle this publisher
// by reducing the publishing frequency
int delayMillis = numPendingTasks < mSubscriber.mMaxPendingTasks
- ? mSubscriber.mPublisherProto.getMemory().getReadIntervalSec() * MILLIS_IN_SECOND
+ ? mSubscriber.mPublisherProto.getReadIntervalSec() * MILLIS_IN_SECOND
: THROTTLE_MILLIS;
// schedule the next Runnable to read meminfo
mTelemetryHandler.postDelayed(mReadMeminfoRunnable, delayMillis);
mTraceLog.traceEnd();
}
+ /**
+ * Helper method to get process meminfo statistics from the declared packages in
+ * {@code mSubscriber}. Each process meminfo is a PersistableBundle and it will be put into the
+ * parameter {@code data};
+ */
+ private void readProcessMeminfo(PersistableBundle data) {
+ mTraceLog.traceBegin("reading process meminfo");
+ // update the throttle time for ActivityManager#getProcessMemoryInfo API call
+ String restore = Settings.Global.getString(
+ mContext.getContentResolver(), ACTIVITY_MANAGER_CONSTANTS);
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ ACTIVITY_MANAGER_CONSTANTS,
+ "memory_info_throttle_time=1");
+ // find PIDs from package names because the API accept an array of PIDs
+ List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
+ mActivityManager.getRunningAppProcesses();
+ // the 2 lists run in parallel, where pidList.get(i) is the pid of the pkgList.get(i)
+ List<Integer> pidList = new ArrayList<>();
+ List<String> bundleKeys = new ArrayList<>();
+ // find PIDs from package names specified by the MetricsConfig
+ for (ActivityManager.RunningAppProcessInfo process : runningAppProcesses) {
+ // Default apps use package name as process name, some apps will have the format
+ // package_name:process_name, so we extract package name and process name with split
+ String[] split = process.processName.split(":");
+ if (mSubscriber.mPackageNames.contains(split[0])) {
+ if (CarTelemetryService.DEBUG) {
+ Slogf.d(CarLog.TAG_TELEMETRY,
+ "MemoryPublisher found matching process " + process.processName);
+ }
+ pidList.add(process.pid);
+ bundleKeys.add(split[0] + ":" + process.uid + ":" + split[split.length - 1]);
+ }
+ }
+
+ // return early if no matching process found
+ if (pidList.size() == 0) {
+ return;
+ }
+
+ // convert ArrayList<Integer> into int[]
+ int[] pids = new int[pidList.size()];
+ for (int i = 0; i < pids.length; i++) {
+ pids[i] = pidList.get(i);
+ }
+ // get process meminfo and parse it into a PersistableBundle
+ Debug.MemoryInfo[] mis = mActivityManager.getProcessMemoryInfo(pids);
+ for (int i = 0; i < mis.length; i++) {
+ Debug.MemoryInfo mi = mis[i];
+ PersistableBundle processMeminfoBundle = new PersistableBundle();
+ processMeminfoBundle.putInt(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+ Integer.valueOf(mi.getTotalSwappablePss()));
+ processMeminfoBundle.putInt(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+ Integer.valueOf(mi.getTotalPrivateDirty()));
+ processMeminfoBundle.putInt(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+ Integer.valueOf(mi.getTotalSharedDirty()));
+ processMeminfoBundle.putInt(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+ Integer.valueOf(mi.getTotalPrivateClean()));
+ processMeminfoBundle.putInt(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+ Integer.valueOf(mi.getTotalSharedClean()));
+ Map<String, String> map = mi.getMemoryStats();
+ for (Map.Entry<String, String> entry : map.entrySet()) {
+ processMeminfoBundle.putInt(Constants.MEMORY_BUNDLE_KEY_PREFIX + entry.getKey(),
+ Integer.valueOf(entry.getValue()));
+ }
+ data.putPersistableBundle(bundleKeys.get(i), processMeminfoBundle);
+ }
+ // restore the settings constant to the original state
+ Settings.Global.putString(mContext.getContentResolver(),
+ ACTIVITY_MANAGER_CONSTANTS, restore);
+ mTraceLog.traceEnd();
+ }
+
private static final class MemorySubscriberWrapper {
/**
* Whether to keep collecting the meminfo snapshots until end of MetricsConfig lifecycle or
@@ -227,18 +345,20 @@
* This flag should be set to true when the max_snapshots field is unspecified in
* {@link TelemetryProto.Publisher}.
*/
- private boolean mCollectIndefinitely;
+ private final boolean mCollectIndefinitely;
+ /**
+ * Maximum number of memory-related pending tasks before throttling this publisher
+ */
+ private final int mMaxPendingTasks;
+ private final DataSubscriber mDataSubscriber;
+ private final TelemetryProto.MetricsConfig mMetricsConfig;
+ private final TelemetryProto.MemoryPublisher mPublisherProto;
+ private final Set<String> mPackageNames = new HashSet<>();
+
/**
* Number of snapshots until the publisher stops collecting data.
*/
private int mNumSnapshotsLeft;
- /**
- * Maximum number of memory-related pending tasks before throttling this publisher
- */
- private int mMaxPendingTasks;
- private DataSubscriber mDataSubscriber;
- private TelemetryProto.MetricsConfig mMetricsConfig;
- private TelemetryProto.Publisher mPublisherProto;
private MemorySubscriberWrapper(
DataSubscriber dataSubscriber, int numSnapshotsLeft, boolean collectIndefinitely) {
@@ -246,8 +366,9 @@
mNumSnapshotsLeft = numSnapshotsLeft;
mCollectIndefinitely = collectIndefinitely;
mMetricsConfig = dataSubscriber.getMetricsConfig();
- mPublisherProto = dataSubscriber.getPublisherParam();
- mMaxPendingTasks = mPublisherProto.getMemory().getMaxPendingTasks();
+ mPublisherProto = dataSubscriber.getPublisherParam().getMemory();
+ mMaxPendingTasks = mPublisherProto.getMaxPendingTasks();
+ mPackageNames.addAll(mPublisherProto.getPackageNamesList());
}
/** Publishes data and returns the number of pending tasks by this publisher. */
@@ -255,7 +376,10 @@
if (mNumSnapshotsLeft > 0) {
mNumSnapshotsLeft--;
}
- return mDataSubscriber.push(data);
+ boolean isLargeData =
+ data.toString().length() >= DataSubscriber.SCRIPT_INPUT_SIZE_THRESHOLD_BYTES
+ ? true : false;
+ return mDataSubscriber.push(data, isLargeData);
}
private boolean isDone() {
diff --git a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
index 546ffea..8866831 100644
--- a/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
+++ b/service/src/com/android/car/telemetry/publisher/PublisherFactory.java
@@ -123,7 +123,7 @@
case TelemetryProto.Publisher.MEMORY_FIELD_NUMBER:
if (mMemoryPublisher == null) {
mMemoryPublisher = new MemoryPublisher(
- mPublisherListener, mTelemetryHandler, mResultStore,
+ mContext, mPublisherListener, mTelemetryHandler, mResultStore,
mSessionController);
}
return mMemoryPublisher;
diff --git a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
index 328ef2c..2897f2c 100644
--- a/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/StatsPublisher.java
@@ -21,6 +21,7 @@
import static com.android.car.telemetry.AtomsProto.Atom.APP_CRASH_OCCURRED_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.Atom.APP_START_MEMORY_STATE_CAPTURED_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_CPU_TIME_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.Atom.WTF_OCCURRED_FIELD_NUMBER;
import static com.android.car.telemetry.CarTelemetryService.DEBUG;
@@ -41,6 +42,7 @@
import com.android.car.CarLog;
import com.android.car.telemetry.AtomsProto.ProcessCpuTime;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
import com.android.car.telemetry.AtomsProto.ProcessMemoryState;
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.StatsLogProto;
@@ -98,6 +100,10 @@
static final long WTF_OCCURRED_ATOM_MATCHER_ID = 13;
@VisibleForTesting
static final long WTF_OCCURRED_EVENT_METRIC_ID = 14;
+ @VisibleForTesting
+ static final long PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID = 15;
+ @VisibleForTesting
+ static final long PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID = 16;
// TODO(b/202115033): Flatten the load spike by pulling reports for each MetricsConfigs
// using separate periodical timers.
@@ -135,6 +141,30 @@
.setField(ProcessCpuTime.SYSTEM_TIME_MILLIS_FIELD_NUMBER))
.build();
+ @VisibleForTesting
+ static final StatsdConfigProto.FieldMatcher PROCESS_MEMORY_SNAPSHOT_FIELDS_MATCHER =
+ StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(
+ PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.PID_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.OOM_SCORE_ADJ_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.RSS_IN_KILOBYTES_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.ANON_RSS_IN_KILOBYTES_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.SWAP_IN_KILOBYTES_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot
+ .ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.GPU_MEMORY_KB_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.HAS_FOREGROUND_SERVICES_FIELD_NUMBER))
+ .build();
+
private final StatsManagerProxy mStatsManager;
private final ResultStore mResultStore;
private final Handler mTelemetryHandler;
@@ -192,12 +222,10 @@
if (!mIsPullingReports) {
if (DEBUG) {
- Slogf.d(CarLog.TAG_TELEMETRY, "Stats report will be pulled in "
- + PULL_REPORTS_PERIOD.toMinutes() + " minutes.");
+ Slogf.d(CarLog.TAG_TELEMETRY, "Triggering pull stats reports");
}
mIsPullingReports = true;
- mTelemetryHandler.postDelayed(
- mPullReportsPeriodically, PULL_REPORTS_PERIOD.toMillis());
+ mTelemetryHandler.post(mPullReportsPeriodically);
}
}
@@ -247,12 +275,17 @@
case WTF_OCCURRED:
metricId = WTF_OCCURRED_EVENT_METRIC_ID;
break;
+ case PROCESS_MEMORY_SNAPSHOT:
+ metricId = PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID;
+ break;
default:
return;
}
if (!metricBundles.containsKey(metricId)) {
Slogf.w(CarLog.TAG_TELEMETRY,
- "No reports for metric id " + metricId + " for config " + configKey);
+ "No reports for metric id " + metricId + " ("
+ + subscriber.getPublisherParam().getStats().getSystemMetric()
+ + ") for config " + configKey);
return;
}
PersistableBundle bundle = metricBundles.get(metricId);
@@ -551,6 +584,8 @@
return buildAnrOccurredStatsdConfig(builder);
case WTF_OCCURRED:
return buildWtfOccurredStatsdConfig(builder);
+ case PROCESS_MEMORY_SNAPSHOT:
+ return buildProcessMemorySnapshotStatsdConfig(builder);
default:
throw new IllegalArgumentException("Unsupported metric " + metric.name());
}
@@ -702,6 +737,39 @@
.build();
}
+ @NonNull
+ private static StatsdConfig buildProcessMemorySnapshotStatsdConfig(
+ @NonNull StatsdConfig.Builder builder) {
+ return builder
+ .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
+ // The id must be unique within StatsdConfig/matchers
+ .setId(PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID)
+ .setSimpleAtomMatcher(StatsdConfigProto.SimpleAtomMatcher.newBuilder()
+ .setAtomId(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)))
+ .addGaugeMetric(StatsdConfigProto.GaugeMetric.newBuilder()
+ // The id must be unique within StatsdConfig/metrics
+ .setId(PROCESS_MEMORY_SNAPSHOT_GAUGE_METRIC_ID)
+ .setWhat(PROCESS_MEMORY_SNAPSHOT_ATOM_MATCHER_ID)
+ .setDimensionsInWhat(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.UID_FIELD_NUMBER))
+ .addChild(StatsdConfigProto.FieldMatcher.newBuilder()
+ .setField(ProcessMemorySnapshot.PROCESS_NAME_FIELD_NUMBER))
+ )
+ .setGaugeFieldsFilter(StatsdConfigProto.FieldFilter.newBuilder()
+ .setFields(PROCESS_MEMORY_SNAPSHOT_FIELDS_MATCHER)
+ ) // setGaugeFieldsFilter
+ .setSamplingType(
+ StatsdConfigProto.GaugeMetric.SamplingType.RANDOM_ONE_SAMPLE)
+ .setBucket(StatsdConfigProto.TimeUnit.FIVE_MINUTES)
+ )
+ .addPullAtomPackages(StatsdConfigProto.PullAtomPackages.newBuilder()
+ .setAtomId(PROCESS_MEMORY_SNAPSHOT_FIELD_NUMBER)
+ .addPackages("AID_SYSTEM"))
+ .build();
+ }
+
@Override
protected void handleSessionStateChange(SessionAnnotation annotation) {}
}
diff --git a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
index 95f9184..8db436a 100644
--- a/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
+++ b/service/src/com/android/car/telemetry/publisher/VehiclePropertyPublisher.java
@@ -16,6 +16,8 @@
package com.android.car.telemetry.publisher;
+import static com.android.car.telemetry.CarTelemetryService.DEBUG;
+
import static java.lang.Integer.toHexString;
import android.annotation.NonNull;
@@ -38,9 +40,11 @@
import com.android.car.CarPropertyService;
import com.android.car.telemetry.databroker.DataSubscriber;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -50,32 +54,12 @@
* property id of the subscriber and starts pushing the change events to the subscriber.
*/
public class VehiclePropertyPublisher extends AbstractPublisher {
- private static final boolean DEBUG = false; // STOPSHIP if true
-
- public static final String BUNDLE_TIMESTAMP_KEY = "timestamp";
- public static final String BUNDLE_STRING_KEY = "stringVal";
- public static final String BUNDLE_BOOLEAN_KEY = "boolVal";
- public static final String BUNDLE_INT_KEY = "intVal";
- public static final String BUNDLE_INT_ARRAY_KEY = "intArrayVal";
- public static final String BUNDLE_LONG_KEY = "longVal";
- public static final String BUNDLE_LONG_ARRAY_KEY = "longArrayVal";
- public static final String BUNDLE_FLOAT_KEY = "floatVal";
- public static final String BUNDLE_FLOAT_ARRAY_KEY = "floatArrayVal";
- public static final String BUNDLE_BYTE_ARRAY_KEY = "byteArrayVal";
private final CarPropertyService mCarPropertyService;
private final Handler mTelemetryHandler;
-
// The class only reads, no need to synchronize this object.
// Maps property_id to CarPropertyConfig.
private final SparseArray<CarPropertyConfig> mCarPropertyList;
-
- // SparseArray and ArraySet are memory optimized, but they can be bit slower for more
- // than 100 items. We're expecting much less number of subscribers, so these DS are ok.
- // Maps property_id to the set of DataSubscriber.
- private final SparseArray<ArraySet<DataSubscriber>> mCarPropertyToSubscribers =
- new SparseArray<>();
-
private final ICarPropertyEventListener mCarPropertyEventListener =
new ICarPropertyEventListener.Stub() {
@Override
@@ -90,6 +74,11 @@
}
};
+ // Maps property id to the PropertyData containing batch of its bundles and subscribers.
+ // Each property is batched separately.
+ private final SparseArray<PropertyData> mPropertyDataLookup = new SparseArray<>();
+ private long mBatchIntervalMillis = 100L; // Batch every 100 milliseconds = 10Hz
+
public VehiclePropertyPublisher(
@NonNull CarPropertyService carPropertyService,
@NonNull PublisherListener listener,
@@ -122,18 +111,18 @@
|| config.getAccess()
== CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE,
"No access. Cannot read " + VehiclePropertyIds.toString(propertyId) + ".");
-
- ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
- if (subscribers == null) {
- subscribers = new ArraySet<>();
- mCarPropertyToSubscribers.put(propertyId, subscribers);
- // Register the listener only once per propertyId.
+ PropertyData propertyData = mPropertyDataLookup.get(propertyId);
+ if (propertyData == null) {
+ propertyData = new PropertyData(config);
+ mPropertyDataLookup.put(propertyId, propertyData);
+ }
+ if (propertyData.subscribers.isEmpty()) {
mCarPropertyService.registerListener(
propertyId,
publisherParam.getVehicleProperty().getReadRate(),
mCarPropertyEventListener);
}
- subscribers.add(subscriber);
+ propertyData.subscribers.add(subscriber);
}
@Override
@@ -146,14 +135,13 @@
return;
}
int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
-
- ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
- if (subscribers == null) {
+ PropertyData propertyData = mPropertyDataLookup.get(propertyId);
+ if (propertyData == null) {
return;
}
- subscribers.remove(subscriber);
- if (subscribers.isEmpty()) {
- mCarPropertyToSubscribers.remove(propertyId);
+ propertyData.subscribers.remove(subscriber);
+ if (propertyData.subscribers.isEmpty()) {
+ mPropertyDataLookup.remove(propertyId);
// Doesn't throw exception as listener is not null. mCarPropertyService and
// local mCarPropertyToSubscribers will not get out of sync.
mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
@@ -162,13 +150,13 @@
@Override
public void removeAllDataSubscribers() {
- for (int i = 0; i < mCarPropertyToSubscribers.size(); i++) {
- int propertyId = mCarPropertyToSubscribers.keyAt(i);
+ for (int i = 0; i < mPropertyDataLookup.size(); i++) {
// Doesn't throw exception as listener is not null. mCarPropertyService and
// local mCarPropertyToSubscribers will not get out of sync.
- mCarPropertyService.unregisterListener(propertyId, mCarPropertyEventListener);
+ mCarPropertyService.unregisterListener(
+ mPropertyDataLookup.keyAt(i), mCarPropertyEventListener);
}
- mCarPropertyToSubscribers.clear();
+ mPropertyDataLookup.clear();
}
@Override
@@ -178,10 +166,18 @@
return false;
}
int propertyId = publisherParam.getVehicleProperty().getVehiclePropertyId();
- ArraySet<DataSubscriber> subscribers = mCarPropertyToSubscribers.get(propertyId);
- return subscribers != null && subscribers.contains(subscriber);
+ return mPropertyDataLookup.contains(propertyId)
+ && mPropertyDataLookup.get(propertyId).subscribers.contains(subscriber);
}
+ @VisibleForTesting
+ public void setBatchIntervalMillis(long intervalMillis) {
+ mBatchIntervalMillis = intervalMillis;
+ }
+
+ @Override
+ protected void handleSessionStateChange(SessionAnnotation annotation) {}
+
/**
* Called when publisher receives new event. It's executed on a CarPropertyService's
* worker thread.
@@ -190,103 +186,127 @@
// move the work from CarPropertyService's worker thread to the telemetry thread
mTelemetryHandler.post(() -> {
CarPropertyValue propValue = event.getCarPropertyValue();
+ int propertyId = propValue.getPropertyId();
+ PropertyData propertyData = mPropertyDataLookup.get(propertyId);
PersistableBundle bundle = parseCarPropertyValue(
- propValue, mCarPropertyList.get(propValue.getPropertyId()).getConfigArray());
- for (DataSubscriber subscriber
- : mCarPropertyToSubscribers.get(propValue.getPropertyId())) {
- subscriber.push(bundle);
+ propValue, propertyData.config.getConfigArray());
+ propertyData.pendingData.add(bundle);
+ if (propertyData.pendingData.size() == 1) {
+ mTelemetryHandler.postDelayed(
+ () -> {
+ pushPendingDataToSubscribers(propertyData);
+ },
+ mBatchIntervalMillis);
}
});
}
/**
+ * Pushes bundle batch to subscribers and resets batch.
+ */
+ private void pushPendingDataToSubscribers(PropertyData propertyData) {
+ for (DataSubscriber subscriber : propertyData.subscribers) {
+ subscriber.push(propertyData.pendingData);
+ }
+ propertyData.pendingData = new ArrayList<>();
+ }
+
+ /**
* Parses the car property value into a PersistableBundle.
*/
private PersistableBundle parseCarPropertyValue(
CarPropertyValue propValue, List<Integer> configArray) {
- Object value = propValue.getValue();
PersistableBundle bundle = new PersistableBundle();
- bundle.putLong(BUNDLE_TIMESTAMP_KEY, propValue.getTimestamp());
+ bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_TIMESTAMP, propValue.getTimestamp());
+ bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_PROP_ID, propValue.getPropertyId());
+ bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_AREA_ID, propValue.getAreaId());
+ bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STATUS, propValue.getStatus());
int type = propValue.getPropertyId() & VehiclePropertyType.MASK;
+ Object value = propValue.getValue();
if (VehiclePropertyType.BOOLEAN == type) {
- bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) value);
+ bundle.putBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN, (Boolean) value);
} else if (VehiclePropertyType.FLOAT == type) {
- bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) value).doubleValue());
+ bundle.putDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT,
+ ((Float) value).doubleValue());
} else if (VehiclePropertyType.INT32 == type) {
- bundle.putInt(BUNDLE_INT_KEY, (Integer) value);
+ bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT, (Integer) value);
} else if (VehiclePropertyType.INT64 == type) {
- bundle.putLong(BUNDLE_LONG_KEY, (Long) value);
+ bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG, (Long) value);
} else if (VehiclePropertyType.FLOAT_VEC == type) {
Float[] floats = (Float[]) value;
double[] doubles = new double[floats.length];
for (int i = 0; i < floats.length; i++) {
doubles[i] = floats[i].doubleValue();
}
- bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+ bundle.putDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY, doubles);
} else if (VehiclePropertyType.INT32_VEC == type) {
Integer[] integers = (Integer[]) value;
int[] ints = new int[integers.length];
for (int i = 0; i < integers.length; i++) {
ints[i] = integers[i];
}
- bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+ bundle.putIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY, ints);
} else if (VehiclePropertyType.INT64_VEC == type) {
Long[] oldLongs = (Long[]) value;
long[] longs = new long[oldLongs.length];
for (int i = 0; i < oldLongs.length; i++) {
longs[i] = oldLongs[i];
}
- bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+ bundle.putLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY, longs);
} else if (VehiclePropertyType.STRING == type) {
- bundle.putString(BUNDLE_STRING_KEY, (String) value);
+ bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING, (String) value);
} else if (VehiclePropertyType.BYTES == type) {
bundle.putString(
- BUNDLE_BYTE_ARRAY_KEY, new String((byte[]) value, StandardCharsets.UTF_8));
+ Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY,
+ new String((byte[]) value, StandardCharsets.UTF_8));
} else if (VehiclePropertyType.MIXED == type) {
Object[] mixed = (Object[]) value;
int k = 0;
if (configArray.get(0) == 1) { // Has single String
- bundle.putString(BUNDLE_STRING_KEY, (String) mixed[k++]);
+ bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING, (String) mixed[k++]);
}
if (configArray.get(1) == 1) { // Has single Boolean
- bundle.putBoolean(BUNDLE_BOOLEAN_KEY, (Boolean) mixed[k++]);
+ bundle.putBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN,
+ (Boolean) mixed[k++]);
}
if (configArray.get(2) == 1) { // Has single Integer
- bundle.putInt(BUNDLE_INT_KEY, (Integer) mixed[k++]);
+ bundle.putInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT, (Integer) mixed[k++]);
}
if (configArray.get(3) != 0) { // Integer[] length is non-zero
int[] ints = new int[configArray.get(3)];
for (int i = 0; i < configArray.get(3); i++) {
ints[i] = (Integer) mixed[k++];
}
- bundle.putIntArray(BUNDLE_INT_ARRAY_KEY, ints);
+ bundle.putIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY, ints);
}
if (configArray.get(4) == 1) { // Has single Long
- bundle.putLong(BUNDLE_LONG_KEY, (Long) mixed[k++]);
+ bundle.putLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG, (Long) mixed[k++]);
}
if (configArray.get(5) != 0) { // Long[] length is non-zero
long[] longs = new long[configArray.get(5)];
for (int i = 0; i < configArray.get(5); i++) {
longs[i] = (Long) mixed[k++];
}
- bundle.putLongArray(BUNDLE_LONG_ARRAY_KEY, longs);
+ bundle.putLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY, longs);
}
if (configArray.get(6) == 1) { // Has single Float
- bundle.putDouble(BUNDLE_FLOAT_KEY, ((Float) mixed[k++]).doubleValue());
+ bundle.putDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT,
+ ((Float) mixed[k++]).doubleValue());
}
if (configArray.get(7) != 0) { // Float[] length is non-zero
double[] doubles = new double[configArray.get(7)];
for (int i = 0; i < configArray.get(7); i++) {
doubles[i] = ((Float) mixed[k++]).doubleValue();
}
- bundle.putDoubleArray(BUNDLE_FLOAT_ARRAY_KEY, doubles);
+ bundle.putDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY, doubles);
}
if (configArray.get(8) != 0) { // Byte[] length is non-zero
byte[] bytes = new byte[configArray.get(8)];
for (int i = 0; i < configArray.get(8); i++) {
bytes[i] = (Byte) mixed[k++];
}
- bundle.putString(BUNDLE_BYTE_ARRAY_KEY, new String(bytes, StandardCharsets.UTF_8));
+ bundle.putString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY,
+ new String(bytes, StandardCharsets.UTF_8));
}
} else {
throw new IllegalArgumentException(
@@ -295,6 +315,19 @@
return bundle;
}
- @Override
- protected void handleSessionStateChange(SessionAnnotation annotation) {}
+ /**
+ * Container class holding all the relevant information for a property.
+ */
+ private static final class PropertyData {
+ // The config containing info on how to parse the property value.
+ public final CarPropertyConfig config;
+ // Subscribers subscribed to the property this PropertyData is mapped to.
+ public final ArraySet<DataSubscriber> subscribers = new ArraySet<>();
+ // The list of bundles that are batched together and pushed to subscribers
+ public List<PersistableBundle> pendingData = new ArrayList<>();
+
+ PropertyData(CarPropertyConfig propConfig) {
+ config = propConfig;
+ }
+ }
}
diff --git a/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java b/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
index 9789254..9d1dccc 100644
--- a/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
+++ b/service/src/com/android/car/telemetry/publisher/net/RefinedStats.java
@@ -23,6 +23,7 @@
import com.android.car.internal.util.IntArray;
import com.android.car.internal.util.LongArray;
import com.android.car.telemetry.UidPackageMapper;
+import com.android.car.telemetry.publisher.Constants;
/**
* Restructured {@link NetworkStats} to simplify subtract/add arithmetics, as well as converting
@@ -147,20 +148,20 @@
@NonNull
public PersistableBundle toPersistableBundle(@NonNull UidPackageMapper uidMapper) {
PersistableBundle data = new PersistableBundle();
- data.putLong("startMillis", mStartMillis);
- data.putLong("endMillis", mEndMillis);
- data.putInt("size", mUid.size());
+ data.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, mStartMillis);
+ data.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, mEndMillis);
+ data.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, mUid.size());
// TODO(b/218596960): send empty array anyway for data schema consistency.
if (mUid.size() > 0) {
- data.putIntArray("uid", mUid.toArray());
+ data.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID, mUid.toArray());
String[] packages = new String[mUid.size()];
for (int i = 0; i < mUid.size(); i++) {
packages[i] = String.join(",", uidMapper.getPackagesForUid(mUid.get(i)));
}
- data.putStringArray("packages", packages);
- data.putIntArray("tag", mTag.toArray());
- data.putLongArray("rxBytes", mRxBytes.toArray());
- data.putLongArray("txBytes", mTxBytes.toArray());
+ data.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES, packages);
+ data.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG, mTag.toArray());
+ data.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES, mRxBytes.toArray());
+ data.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES, mTxBytes.toArray());
}
return data;
}
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
index c01d483..14d969d 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/AbstractAtomConverter.java
@@ -16,6 +16,8 @@
package com.android.car.telemetry.publisher.statsconverters;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.PersistableBundle;
@@ -123,7 +125,7 @@
valueList.add(atomFieldAccessor.getField(atomData));
}
setPersistableBundleArrayField(
- atomFieldAccessor.getFieldName(), valueList, bundle);
+ createBundleKey(atomFieldAccessor.getFieldName()), valueList, bundle);
}
}
// Check if there are dimension fields needing conversion
@@ -139,7 +141,7 @@
valueList.add(extractDimensionsValue(dvList.get(i), hashToStringMap));
}
setPersistableBundleArrayField(
- getAtomFieldAccessorMap().get(fieldId).getFieldName(),
+ createBundleKey(getAtomFieldAccessorMap().get(fieldId).getFieldName()),
valueList,
bundle);
}
@@ -227,4 +229,16 @@
bundle.putDoubleArray(name, doubleArray);
}
}
+
+ /**
+ * Creates the bundle key string for a metric field.
+ *
+ * The bundle key differs from the original metric field name by having a namespace prefix.
+ *
+ * @param metricFieldName the metric field name string.
+ * @return the bundle key string.
+ */
+ private String createBundleKey(String metricFieldName) {
+ return STATS_BUNDLE_KEY_PREFIX + metricFieldName;
+ }
}
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
index c9227f5..85e0eae 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverter.java
@@ -44,7 +44,8 @@
// Map of pulled atom cases to corresponding atom converter.
private static Map<Atom.PulledCase, AbstractAtomConverter<?>> sPulledCaseConverters = Map.of(
Atom.PulledCase.PROCESS_MEMORY_STATE, new ProcessMemoryStateConverter(),
- Atom.PulledCase.PROCESS_CPU_TIME, new ProcessCpuTimeConverter());
+ Atom.PulledCase.PROCESS_CPU_TIME, new ProcessCpuTimeConverter(),
+ Atom.PulledCase.PROCESS_MEMORY_SNAPSHOT, new ProcessMemorySnapshotConverter());
/**
* Converts a list of atoms to separate the atoms fields values into arrays to be put into the
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
index 38be940..ad72e73 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverter.java
@@ -16,6 +16,8 @@
package com.android.car.telemetry.publisher.statsconverters;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+
import android.annotation.NonNull;
import android.os.PersistableBundle;
@@ -29,8 +31,6 @@
* Class for converting event metric data to {@link PersistableBundle} compatible format.
*/
public class EventMetricDataConverter {
- static final String ELAPSED_TIME_NANOS = "elapsed_timestamp_nanos";
-
/**
* Converts a list of {@link StatsLogProto.EventMetricData} to {@link PersistableBundle} format
* such that along with the elapsed time array each field of the atom has an associated array
@@ -67,7 +67,7 @@
for (int i = 0; i < elapsedTimes.size(); ++i) {
elapsedTimesArray[i] = elapsedTimes.get(i);
}
- bundle.putLongArray(ELAPSED_TIME_NANOS, elapsedTimesArray);
+ bundle.putLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP, elapsedTimesArray);
return bundle;
}
}
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
index cc29aa4..d260e04 100644
--- a/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverter.java
@@ -16,6 +16,8 @@
package com.android.car.telemetry.publisher.statsconverters;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.PersistableBundle;
@@ -34,8 +36,6 @@
* Class for converting gauge metric data to {@link PersistableBundle} compatible format.
*/
public class GaugeMetricDataConverter {
- static final String ELAPSED_TIME_NANOS = "elapsed_timestamp_nanos";
-
/**
* Converts a list of {@link StatsLogProto.GaugeMetricData} to {@link PersistableBundle}
* format such that along with the elapsed time array each field of the atom has an associated
@@ -97,7 +97,7 @@
for (int i = 0; i < elapsedTimes.size(); ++i) {
elapsedTimesArray[i] = elapsedTimes.get(i);
}
- bundle.putLongArray(ELAPSED_TIME_NANOS, elapsedTimesArray);
+ bundle.putLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP, elapsedTimesArray);
return bundle;
}
}
diff --git a/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java b/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java
new file mode 100644
index 0000000..42845e8
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverter.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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.publisher.statsconverters;
+
+import android.annotation.NonNull;
+import android.util.SparseArray;
+
+import com.android.car.telemetry.AtomsProto.Atom;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Atom data converter for atoms of type {@link ProcessMemorySnapshot}.
+ */
+public class ProcessMemorySnapshotConverter extends AbstractAtomConverter<ProcessMemorySnapshot> {
+
+ private static final SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>>
+ sAtomFieldAccessorMap = new SparseArray<>();
+ static {
+ sAtomFieldAccessorMap.append(1, new AtomFieldAccessor<>(
+ "uid",
+ a -> a.hasUid(),
+ a -> a.getUid()
+ ));
+ sAtomFieldAccessorMap.append(2, new AtomFieldAccessor<>(
+ "process_name",
+ a -> a.hasProcessName(),
+ a -> a.getProcessName()
+ ));
+ sAtomFieldAccessorMap.append(3, new AtomFieldAccessor<>(
+ "pid",
+ a -> a.hasPid(),
+ a -> a.getPid()
+ ));
+ sAtomFieldAccessorMap.append(4, new AtomFieldAccessor<>(
+ "oom_score_adj",
+ a -> a.hasOomScoreAdj(),
+ a -> a.getOomScoreAdj()
+ ));
+ sAtomFieldAccessorMap.append(5, new AtomFieldAccessor<>(
+ "rss_in_kilobytes",
+ a -> a.hasRssInKilobytes(),
+ a -> a.getRssInKilobytes()
+ ));
+ sAtomFieldAccessorMap.append(6, new AtomFieldAccessor<>(
+ "anon_rss_in_kilobytes",
+ a -> a.hasAnonRssInKilobytes(),
+ a -> a.getAnonRssInKilobytes()
+ ));
+ sAtomFieldAccessorMap.append(7, new AtomFieldAccessor<>(
+ "swap_in_kilobytes",
+ a -> a.hasSwapInKilobytes(),
+ a -> a.getSwapInKilobytes()
+ ));
+ sAtomFieldAccessorMap.append(8, new AtomFieldAccessor<>(
+ "anon_rss_and_swap_in_kilobytes",
+ a -> a.hasAnonRssAndSwapInKilobytes(),
+ a -> a.getAnonRssAndSwapInKilobytes()
+ ));
+ sAtomFieldAccessorMap.append(9, new AtomFieldAccessor<>(
+ "gpu_memory_kb",
+ a -> a.hasGpuMemoryKb(),
+ a -> a.getGpuMemoryKb()
+ ));
+ sAtomFieldAccessorMap.append(10, new AtomFieldAccessor<>(
+ "has_foreground_services",
+ a -> a.hasHasForegroundServices(),
+ a -> a.getHasForegroundServices()
+ ));
+ }
+
+ ProcessMemorySnapshotConverter() {
+ super();
+ }
+
+ @NonNull
+ @Override
+ SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>> getAtomFieldAccessorMap() {
+ return sAtomFieldAccessorMap;
+ }
+
+ @NonNull
+ @Override
+ ProcessMemorySnapshot getAtomData(@NonNull Atom atom) {
+ Preconditions.checkArgument(
+ atom.hasProcessMemorySnapshot(), "Atom doesn't contain ProcessMemorySnapshot");
+ return atom.getProcessMemorySnapshot();
+ }
+
+ @NonNull
+ @Override
+ String getAtomDataClassName() {
+ return ProcessMemorySnapshot.class.getSimpleName();
+ }
+}
diff --git a/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl b/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl
new file mode 100644
index 0000000..89e7d1d
--- /dev/null
+++ b/service/src/com/android/car/telemetry/scriptexecutorinterface/BundleList.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, 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.scriptexecutorinterface;
+
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+
+parcelable BundleList {
+ List<PersistableBundle> bundles;
+
+ // Used by LargeParcelable for SharedMemory allocation
+ @nullable ParcelFileDescriptor sharedMemoryFd;
+}
\ No newline at end of file
diff --git a/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl b/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
index 3101634..86bc1b7 100644
--- a/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
+++ b/service/src/com/android/car/telemetry/scriptexecutorinterface/IScriptExecutor.aidl
@@ -18,6 +18,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
/**
@@ -59,4 +60,22 @@
in ParcelFileDescriptor publishedDataFileDescriptor,
in @nullable PersistableBundle savedState,
in IScriptExecutorListener listener);
+
+ /**
+ * Executes a specified function in a provided Lua script with given input arguments.
+ * This is a specialized version of invokeScript API above for sending a list of bundles. The
+ * data is delivered use LargeParcelable so it can handle large data sizes automatically.
+ *
+ * @param scriptBody complete body of Lua script that also contains the function to be invoked
+ * @param functionName the name of the function to execute
+ * @param bundleList the list of bundles as input data which the scripts will handle
+ * @param savedState key-value pairs preserved from the previous invocation of the function
+ * @param listener callback for the sandboxed environment to report back script execution results,
+ * errors, and logs
+ */
+ void invokeScriptForBundleList(String scriptBody,
+ String functionName,
+ in BundleList bundleList,
+ in @nullable PersistableBundle savedState,
+ in IScriptExecutorListener listener);
}
diff --git a/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java b/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
index 7e4d44c..d24e06d 100644
--- a/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
+++ b/service/src/com/android/car/telemetry/sessioncontroller/SessionAnnotation.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.os.PersistableBundle;
+import com.android.car.telemetry.publisher.Constants;
+
import java.util.Objects;
/**
@@ -27,13 +29,6 @@
* respective public fields are equal by value.
*/
public class SessionAnnotation {
- public static final String ANNOTATION_BUNDLE_KEY_SESSION_ID = "sessionId";
- public static final String ANNOTATION_BUNDLE_KEY_SESSION_STATE = "sessionState";
- public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS =
- "createdAtSinceBootMillis";
- public static final String ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS = "createdAtMillis";
- public static final String ANNOTATION_BUNDLE_KEY_BOOT_REASON = "bootReason";
-
public final int sessionId;
public final int sessionState;
public final long createdAtSinceBootMillis; // Milliseconds since boot.
@@ -66,15 +61,15 @@
public String toString() {
return new StringBuilder()
.append("{")
- .append(ANNOTATION_BUNDLE_KEY_SESSION_ID).append(": ")
+ .append(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID).append(": ")
.append(sessionId).append(", ")
- .append(ANNOTATION_BUNDLE_KEY_SESSION_STATE).append(": ")
+ .append(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE).append(": ")
.append(sessionState).append(", ")
- .append(ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS).append(": ")
+ .append(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS).append(": ")
.append(createdAtSinceBootMillis).append(", ")
- .append(ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS).append(": ")
+ .append(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS).append(": ")
.append(createdAtMillis).append(", ")
- .append(ANNOTATION_BUNDLE_KEY_BOOT_REASON).append(": ")
+ .append(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON).append(": ")
.append(bootReason)
.append("}")
.toString();
@@ -107,12 +102,12 @@
* @param bundle A {@link PersistableBundle} that we want to get the annotations to.
*/
public void addAnnotationsToBundle(@NonNull PersistableBundle bundle) {
- bundle.putInt(ANNOTATION_BUNDLE_KEY_SESSION_ID, sessionId);
- bundle.putInt(ANNOTATION_BUNDLE_KEY_SESSION_STATE, sessionState);
- bundle.putLong(ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS,
+ bundle.putInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID, sessionId);
+ bundle.putInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE, sessionState);
+ bundle.putLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS,
createdAtSinceBootMillis);
- bundle.putLong(ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS, createdAtMillis);
- bundle.putString(ANNOTATION_BUNDLE_KEY_BOOT_REASON, bootReason);
+ bundle.putLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS, createdAtMillis);
+ bundle.putString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON, bootReason);
}
}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index fc5787a..8f3475f 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -101,6 +101,13 @@
"com.android.car.watchdog.ACTION_LAUNCH_APP_SETTINGS";
static final String ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION =
"com.android.car.watchdog.ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION";
+ // TODO(b/244474850): Delete the intent in W release. After TM-QPR2, it is not used anymore by
+ // the notification helper.
+ /**
+ * @deprecated - Prefer dismissing resource over notifications using the
+ * {@code ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION} intent action.
+ */
+ @Deprecated
static final String ACTION_RESOURCE_OVERUSE_DISABLE_APP =
"com.android.car.watchdog.ACTION_RESOURCE_OVERUSE_DISABLE_APP";
@@ -225,6 +232,8 @@
// to database until after shutdown enter.
mWatchdogPerfHandler.writeToDatabase();
break;
+ case PowerCycle.POWER_CYCLE_SUSPEND_EXIT:
+ break;
// ON covers resume.
case PowerCycle.POWER_CYCLE_RESUME:
// There might be outdated & incorrect info. We should reset them before
@@ -587,8 +596,8 @@
}
private void notifyPowerCycleChange(@PowerCycle int powerCycle) {
- if (powerCycle == PowerCycle.NUM_POWER_CYLES) {
- Slogf.e(TAG, "Skipping notifying invalid power cycle (%d)", powerCycle);
+ if (!Car.getPlatformVersion().isAtLeast(VERSION_CODES.TIRAMISU_2)
+ && powerCycle == PowerCycle.POWER_CYCLE_SUSPEND_EXIT) {
return;
}
try {
@@ -649,7 +658,7 @@
if (powerService != null) {
int powerState = powerService.getPowerState();
int powerCycle = carPowerStateToPowerCycle(powerState);
- if (powerCycle != PowerCycle.NUM_POWER_CYLES) {
+ if (powerCycle >= 0) {
notifyPowerCycleChange(powerCycle);
} else {
Slogf.i(TAG, "Skipping notifying %d power state", powerState);
@@ -799,7 +808,7 @@
Context.RECEIVER_NOT_EXPORTED);
}
- private static @PowerCycle int carPowerStateToPowerCycle(int powerState) {
+ private static int carPowerStateToPowerCycle(int powerState) {
switch (powerState) {
// SHUTDOWN_PREPARE covers suspend and shutdown.
case CarPowerManager.STATE_SHUTDOWN_PREPARE:
@@ -808,11 +817,14 @@
case CarPowerManager.STATE_SUSPEND_ENTER:
case CarPowerManager.STATE_HIBERNATION_ENTER:
return PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER;
+ case CarPowerManager.STATE_SUSPEND_EXIT:
+ case CarPowerManager.STATE_HIBERNATION_EXIT:
+ return PowerCycle.POWER_CYCLE_SUSPEND_EXIT;
// ON covers resume.
case CarPowerManager.STATE_ON:
return PowerCycle.POWER_CYCLE_RESUME;
}
- return PowerCycle.NUM_POWER_CYLES;
+ return -1;
}
private static String toGarageModeString(@GarageMode int garageMode) {
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index c0874dc9..54dbaee 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -377,6 +377,7 @@
* TODO(b/183436216): Implement this method.
*/
synchronized (mLock) {
+ writer.println("Current UX state: " + toUxStateString(mCurrentUxState));
writer.println("List of disabled packages per user due to resource overuse: "
+ mDisabledUserPackagesByUserId);
}
@@ -2634,6 +2635,19 @@
}
}
+ private static String toUxStateString(@UxStateType int uxState) {
+ switch (uxState) {
+ case UX_STATE_NO_DISTRACTION:
+ return "UX_STATE_NO_DISTRACTION";
+ case UX_STATE_USER_NOTIFICATION:
+ return "UX_STATE_USER_NOTIFICATION";
+ case UX_STATE_NO_INTERACTION:
+ return "UX_STATE_NO_INTERACTION";
+ default:
+ return "UNKNOWN UX STATE";
+ }
+ }
+
private final class PackageResourceUsage {
public final String genericPackageName;
public @UserIdInt final int userId;
diff --git a/tests/BugReportApp/res/values-en-rCA/strings.xml b/tests/BugReportApp/res/values-en-rCA/strings.xml
index d8e579d..02e32cd 100644
--- a/tests/BugReportApp/res/values-en-rCA/strings.xml
+++ b/tests/BugReportApp/res/values-en-rCA/strings.xml
@@ -17,24 +17,24 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="2596316479611335185">"Bug Report"</string>
+ <string name="app_name" msgid="2596316479611335185">"Bug report"</string>
<string name="bugreport_info_quit" msgid="5590138890181142473">"Close"</string>
- <string name="bugreport_info_start" msgid="667324824650830832">"Start Bug Report"</string>
+ <string name="bugreport_info_start" msgid="667324824650830832">"Start bug report"</string>
<string name="bugreport_info_status" msgid="7211044508792815451">"Status:"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"This bug report will expire soon"</string>
<string name="bugreport_dialog_submit" msgid="2789636252713280633">"Submit"</string>
<string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Cancel"</string>
<string name="bugreport_dialog_upload" msgid="2517386929450370781">"Upload"</string>
<string name="bugreport_dialog_save" msgid="3291363266190644226">"Save"</string>
- <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show Bug Reports"</string>
+ <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Show bug reports"</string>
<string name="bugreport_dialog_close" msgid="289925437277364266">"Close"</string>
- <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak & Describe The Issue"</string>
+ <string name="bugreport_dialog_title" msgid="3315160684205929910">"Speak and describe the issue"</string>
<string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Audio message for bug report at %s"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Recording finished"</string>
<string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Bug report is in progress"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"A bug report has been collected"</string>
- <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add Audio"</string>
- <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add Audio & Upload"</string>
+ <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Add audio"</string>
+ <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Add audio and upload"</string>
<string name="bugreport_move_button_text" msgid="1245698439228323880">"Move to USB"</string>
<string name="bugreport_upload_button_text" msgid="4136749466634820848">"Upload"</string>
<string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Upload to GCS"</string>
diff --git a/tests/BugReportApp/res/values-hy/strings.xml b/tests/BugReportApp/res/values-hy/strings.xml
index 41ecfac..e39e460 100644
--- a/tests/BugReportApp/res/values-hy/strings.xml
+++ b/tests/BugReportApp/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="2596316479611335185">"Հաղորդում վրիպակի մասին"</string>
<string name="bugreport_info_quit" msgid="5590138890181142473">"Փակել"</string>
- <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին հաղորդումը"</string>
+ <string name="bugreport_info_start" msgid="667324824650830832">"Գործարկել վրիպակի մասին զեկույցը"</string>
<string name="bugreport_info_status" msgid="7211044508792815451">"Կարգավիճակը՝"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Վրիպակի մասին այս հաղորդման ժամկետը շուտով կլրանա"</string>
<string name="bugreport_dialog_submit" msgid="2789636252713280633">"Ուղարկել"</string>
@@ -31,7 +31,7 @@
<string name="bugreport_dialog_title" msgid="3315160684205929910">"Բարձրաձայն նկարագրեք սխալը"</string>
<string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Վրիպակների մասին հաշվետվության վերաբերյալ ձայնային հաղորդագրություն, ժամը՝ %s։"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Գրանցումն ավարտվեց"</string>
- <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
+ <string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"Սխալի մասին զեկույցը բեռնվել է"</string>
<string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Ավելացնել աուդիո"</string>
<string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Ավելացնել աուդիո և վերբեռնել"</string>
@@ -39,12 +39,12 @@
<string name="bugreport_upload_button_text" msgid="4136749466634820848">"Վերբեռնել"</string>
<string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Վերբեռնել GCS"</string>
<string name="toast_permissions_denied" msgid="7054832711916992770">"Տրամադրեք թույլտվություններ"</string>
- <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
- <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին հաղորդումը ստեղծվում է"</string>
+ <string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+ <string name="toast_bug_report_started" msgid="891404618481185195">"Վրիպակի մասին զեկույցը ստեղծվում է"</string>
<string name="toast_status_failed" msgid="6365384202315043395">"Վրիպակի զեկույցի հետ կապված սխալ առաջացավ"</string>
<string name="toast_status_screencap_failed" msgid="2187083897594745149">"Չհաջողվեց ստեղծել սքրինշոթ"</string>
<string name="toast_status_dump_state_failed" msgid="3496460783060512078">"Dumpstate ծառայության սխալ"</string>
- <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին հաղորդումը բեռնվում է"</string>
- <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին հաղորդումը բեռնվել է"</string>
- <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին հաղորդման կարգավիճակի ալիք"</string>
+ <string name="notification_bugreport_in_progress" msgid="8486454116357963238">"Վրիպակի մասին զեկույցը բեռնվում է"</string>
+ <string name="notification_bugreport_finished_title" msgid="1188447311929693472">"Վրիպակի մասին զեկույցը բեռնվել է"</string>
+ <string name="notification_bugreport_channel_name" msgid="776902295433824255">"Վրիպակի մասին զեկույցի կարգավիճակի ալիք"</string>
</resources>
diff --git a/tests/BugReportApp/res/values-kn/strings.xml b/tests/BugReportApp/res/values-kn/strings.xml
index 0b5dd81..77e563c 100644
--- a/tests/BugReportApp/res/values-kn/strings.xml
+++ b/tests/BugReportApp/res/values-kn/strings.xml
@@ -29,7 +29,7 @@
<string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ಬಗ್ ವರದಿಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="bugreport_dialog_close" msgid="289925437277364266">"ಮುಚ್ಚಿರಿ"</string>
<string name="bugreport_dialog_title" msgid="3315160684205929910">"ಸಮಸ್ಯೆಯ ಕುರಿತು ಮಾತನಾಡಿ ಮತ್ತು ವಿವರಿಸಿ"</string>
- <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೋ ಸಂದೇಶ"</string>
+ <string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"%s ನಲ್ಲಿ ಬಗ್ ವರದಿ ಮಾಡುವಿಕೆಗಾಗಿ ಆಡಿಯೊ ಸಂದೇಶ"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"ರೆಕಾರ್ಡಿಂಗ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"ಬಗ್ ವರದಿಮಾಡುವಿಕೆ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿದೆ"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"ಬಗ್ ವರದಿಯನ್ನು ಸಂಗ್ರಹಿಸಲಾಗಿದೆ"</string>
diff --git a/tests/BugReportApp/res/values-or/strings.xml b/tests/BugReportApp/res/values-or/strings.xml
index d4a7771..79ce668 100644
--- a/tests/BugReportApp/res/values-or/strings.xml
+++ b/tests/BugReportApp/res/values-or/strings.xml
@@ -23,7 +23,7 @@
<string name="bugreport_info_status" msgid="7211044508792815451">"ସ୍ଥିତି:"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"ଏହି ବଗ୍ ରିପୋର୍ଟର ମିଆଦ ଶୀଘ୍ର ସମାପ୍ତ ହେବ"</string>
<string name="bugreport_dialog_submit" msgid="2789636252713280633">"ଦାଖଲ କରନ୍ତୁ"</string>
- <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ କରନ୍ତୁ"</string>
+ <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="bugreport_dialog_upload" msgid="2517386929450370781">"ଅପ୍ଲୋଡ୍"</string>
<string name="bugreport_dialog_save" msgid="3291363266190644226">"ସେଭ୍ କରନ୍ତୁ"</string>
<string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"ବଗ୍ ରିପୋର୍ଟ୍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
diff --git a/tests/BugReportApp/res/values-ro/strings.xml b/tests/BugReportApp/res/values-ro/strings.xml
index 01790c9..490a056 100644
--- a/tests/BugReportApp/res/values-ro/strings.xml
+++ b/tests/BugReportApp/res/values-ro/strings.xml
@@ -18,27 +18,27 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="2596316479611335185">"Raport de eroare"</string>
- <string name="bugreport_info_quit" msgid="5590138890181142473">"Închide"</string>
- <string name="bugreport_info_start" msgid="667324824650830832">"Începe raportul de eroare"</string>
+ <string name="bugreport_info_quit" msgid="5590138890181142473">"Închideți"</string>
+ <string name="bugreport_info_start" msgid="667324824650830832">"Începeți raportul de eroare"</string>
<string name="bugreport_info_status" msgid="7211044508792815451">"Stare:"</string>
<string name="bugreport_info_expires_soon_notice" msgid="927139313070992675">"Acest raport de eroare va expira în curând"</string>
- <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimite"</string>
- <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulează"</string>
- <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încarcă"</string>
- <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvează"</string>
- <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișează rapoartele de eroare"</string>
- <string name="bugreport_dialog_close" msgid="289925437277364266">"Închide"</string>
- <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbește și descrie problema"</string>
+ <string name="bugreport_dialog_submit" msgid="2789636252713280633">"Trimiteți"</string>
+ <string name="bugreport_dialog_cancel" msgid="4741928791364757040">"Anulați"</string>
+ <string name="bugreport_dialog_upload" msgid="2517386929450370781">"Încărcați"</string>
+ <string name="bugreport_dialog_save" msgid="3291363266190644226">"Salvați"</string>
+ <string name="bugreport_dialog_show_bugreports" msgid="6964385141627170297">"Afișați rapoartele de eroare"</string>
+ <string name="bugreport_dialog_close" msgid="289925437277364266">"Închideți"</string>
+ <string name="bugreport_dialog_title" msgid="3315160684205929910">"Vorbiți și descrieți problema"</string>
<string name="bugreport_dialog_add_audio_to_existing" msgid="4958460267276935700">"Mesaj audio pentru raportul de eroare la %s"</string>
<string name="bugreport_dialog_recording_finished" msgid="3982335902169398758">"Înregistrarea s-a încheiat"</string>
<string name="bugreport_dialog_in_progress_title" msgid="1663500052146177338">"Raportul de eroare este în curs"</string>
<string name="bugreport_dialog_in_progress_title_finished" msgid="1610236990020413471">"S-a colectat un raport de eroare"</string>
- <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adaugă conținut audio"</string>
- <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adaugă conținut audio și încarcă"</string>
- <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mută pe USB"</string>
- <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încarcă"</string>
- <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încarcă în GCS"</string>
- <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordă permisiuni"</string>
+ <string name="bugreport_add_audio_button_text" msgid="8606400151705699144">"Adăugați conținut audio"</string>
+ <string name="bugreport_add_audio_upload_button_text" msgid="3830917832551764694">"Adăugați conținut audio și încărcați"</string>
+ <string name="bugreport_move_button_text" msgid="1245698439228323880">"Mutați pe USB"</string>
+ <string name="bugreport_upload_button_text" msgid="4136749466634820848">"Încărcați"</string>
+ <string name="bugreport_upload_gcs_button_text" msgid="5844929656507607424">"Încărcați în GCS"</string>
+ <string name="toast_permissions_denied" msgid="7054832711916992770">"Acordați permisiuni"</string>
<string name="toast_bug_report_in_progress" msgid="5218530088025955746">"Raportul de eroare este în curs"</string>
<string name="toast_bug_report_started" msgid="891404618481185195">"Raportul de eroare a fost inițiat"</string>
<string name="toast_status_failed" msgid="6365384202315043395">"Raportul de eroare nu s-a realizat"</string>
diff --git a/tests/CarEvsCameraPreviewApp/Android.bp b/tests/CarEvsCameraPreviewApp/Android.bp
index fea6aaf..a570123 100644
--- a/tests/CarEvsCameraPreviewApp/Android.bp
+++ b/tests/CarEvsCameraPreviewApp/Android.bp
@@ -43,11 +43,14 @@
},
libs: [
+ "android.car",
"android.car-system-stubs",
- "androidx.annotation_annotation",
],
- static_libs: ["androidx.annotation_annotation"],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "car-evs-helper-lib",
+ ],
// To make this app be able to re-installed
use_embedded_native_libs: true,
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java
deleted file mode 100644
index 0383b74..0000000
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraGLSurfaceView.java
+++ /dev/null
@@ -1,55 +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.google.android.car.evs;
-
-import android.content.Context;
-import android.opengl.GLSurfaceView;
-import android.view.MotionEvent;
-
-/**
- * GPU-backed SurfaceView to render a hardware buffer described by CarEvsBufferDescriptor.
- */
-public final class CarEvsCameraGLSurfaceView extends GLSurfaceView {
- private static final String TAG = CarEvsCameraGLSurfaceView.class.getSimpleName();
-
- private final GLES20CarEvsCameraPreviewRenderer mRenderer;
-
- public CarEvsCameraGLSurfaceView(Context context, CarEvsCameraPreviewActivity activity) {
- super(context);
- setEGLContextClientVersion(2);
-
- mRenderer = new GLES20CarEvsCameraPreviewRenderer(context, activity);
- setRenderer(mRenderer);
-
- setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- float x = e.getX();
- float y = e.getY();
-
- // Update a location of a text to tell the rearview is not available.
- mRenderer.setTextLocation(x, y);
-
- return true;
- }
-
- public void clearBuffer() {
- mRenderer.clearBuffer();
- }
-}
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
index f5c9337..4bdcf03 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
+++ b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/CarEvsCameraPreviewActivity.java
@@ -44,12 +44,26 @@
import androidx.annotation.GuardedBy;
+import com.android.car.internal.evs.CarEvsGLSurfaceView;
+import com.android.car.internal.evs.GLES20CarEvsBufferRenderer;
+
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-public class CarEvsCameraPreviewActivity extends Activity {
+public class CarEvsCameraPreviewActivity extends Activity
+ implements CarEvsGLSurfaceView.BufferCallback {
+
private static final String TAG = CarEvsCameraPreviewActivity.class.getSimpleName();
+ /**
+ * ActivityManagerService encodes the reason for a request to close system dialogs with this
+ * key.
+ */
+ private final static String EXTRA_DIALOG_CLOSE_REASON = "reason";
+ /** This string literal is from com.android.systemui.car.systembar.CarSystemBarButton class. */
+ private final static String DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON = "carsystembarbutton";
+ /** This string literal is from com.android.server.policy.PhoneWindowManager class. */
+ private final static String DIALOG_CLOSE_REASON_HOME_KEY = "homekey";
/**
* Defines internal states.
@@ -88,7 +102,7 @@
private final ExecutorService mCallbackExecutor = Executors.newFixedThreadPool(1);
/** GL backed surface view to render the camera preview */
- private CarEvsCameraGLSurfaceView mEvsView;
+ private CarEvsGLSurfaceView mEvsView;
private ViewGroup mRootView;
private LinearLayout mPreviewContainer;
@@ -133,7 +147,7 @@
if (mStreamState == STREAM_STATE_INVISIBLE) {
// When the activity becomes invisible (e.g. goes background), we immediately
// returns received frame buffers instead of stopping a video stream.
- returnBufferLocked(buffer);
+ doneWithBufferLocked(buffer);
} else {
// Enqueues a new frame and posts a rendering job
mBufferQueue.add(buffer);
@@ -199,6 +213,17 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ String reason = extras.getString(EXTRA_DIALOG_CLOSE_REASON);
+ if (!DIALOG_CLOSE_REASON_CAR_SYSTEMBAR_BUTTON.equals(reason) &&
+ !DIALOG_CLOSE_REASON_HOME_KEY.equals(reason)) {
+ Log.i(TAG, "Ignore a request to close the system dialog with a reason = " +
+ reason);
+ return;
+ }
+ Log.d(TAG, "Requested to close the dialog, reason = " + reason);
+ }
finish();
} else {
Log.e(TAG, "Unexpected intent " + intent);
@@ -213,7 +238,7 @@
// Need to register the receiver for all users, because we want to receive the Intent after
// the user is changed.
registerReceiverForAllUsers(mBroadcastReceiver, filter, /* broadcastPermission= */ null,
- /* scheduler= */ null, Context.RECEIVER_NOT_EXPORTED);
+ /* scheduler= */ null, Context.RECEIVER_EXPORTED);
}
@Override
@@ -235,7 +260,8 @@
Car.createCar(getApplicationContext(), /* handler = */ null,
Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, mCarServiceLifecycleListener);
- mEvsView = new CarEvsCameraGLSurfaceView(getApplication(), this);
+ mEvsView = CarEvsGLSurfaceView.create(getApplication(), this, getApplicationContext()
+ .getResources().getInteger(R.integer.config_evsRearviewCameraInPlaneRotationAngle));
mRootView = (ViewGroup) LayoutInflater.from(this).inflate(
R.layout.evs_preview_activity, /* root= */ null);
mPreviewContainer = mRootView.findViewById(R.id.evs_preview_container);
@@ -419,8 +445,8 @@
return state;
}
- /** Get a new frame */
- CarEvsBufferDescriptor getNewFrame() {
+ @Override
+ public CarEvsBufferDescriptor onBufferRequested() {
synchronized (mLock) {
if (mBufferQueue.isEmpty()) {
return null;
@@ -435,15 +461,15 @@
}
}
- /** Request to return a buffer we're done with */
- void returnBuffer(CarEvsBufferDescriptor buffer) {
+ @Override
+ public void onBufferProcessed(CarEvsBufferDescriptor buffer) {
synchronized (mLock) {
- returnBufferLocked(buffer);
+ doneWithBufferLocked(buffer);
}
}
@GuardedBy("mLock")
- private void returnBufferLocked(CarEvsBufferDescriptor buffer) {
+ private void doneWithBufferLocked(CarEvsBufferDescriptor buffer) {
try {
mEvsManager.returnFrameBuffer(buffer);
} catch (Exception e) {
diff --git a/tests/CarTelemetryApp/Android.bp b/tests/CarTelemetryApp/Android.bp
index b75a8c7..eebb6a8 100644
--- a/tests/CarTelemetryApp/Android.bp
+++ b/tests/CarTelemetryApp/Android.bp
@@ -22,8 +22,15 @@
srcs: [
"src/**/*.java",
+ "src/**/*.aidl",
":cartelemetryservice-proto-srcs"
],
+ aidl: {
+ local_include_dirs: ["src"],
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ ],
+ },
platform_apis: true,
aaptflags: ["--auto-add-overlay"],
privileged: true,
diff --git a/tests/CarTelemetryApp/AndroidManifest.xml b/tests/CarTelemetryApp/AndroidManifest.xml
index d827fa3..8006ad8 100644
--- a/tests/CarTelemetryApp/AndroidManifest.xml
+++ b/tests/CarTelemetryApp/AndroidManifest.xml
@@ -17,6 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.car.cartelemetryapp">
<uses-permission android:name="android.car.permission.USE_CAR_TELEMETRY_SERVICE"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<application
android:icon="@drawable/ic_launcher"
@@ -37,6 +38,7 @@
</activity>
<service
android:name=".CarMetricsCollectorService"
- android:exported="true"/>
+ android:exported="true"
+ android:singleUser="true" />
</application>
</manifest>
diff --git a/tests/CarTelemetryApp/res/layout/list_item.xml b/tests/CarTelemetryApp/res/layout/list_item.xml
index f975b3c..40a67f2 100644
--- a/tests/CarTelemetryApp/res/layout/list_item.xml
+++ b/tests/CarTelemetryApp/res/layout/list_item.xml
@@ -21,11 +21,30 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
+ android:id="@+id/add_config_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/add_button"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/barrier2" />
+ <Button
+ android:id="@+id/remove_config_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/remove_button"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintEnd_toStartOf="@+id/guideline"
+ app:layout_constraintStart_toEndOf="@+id/add_config_button"
+ app:layout_constraintTop_toTopOf="@+id/barrier2" />
+ <Button
android:id="@+id/show_info_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/history_button"
- app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintStart_toEndOf="@+id/guideline"
+ app:layout_constraintEnd_toStartOf="@+id/clear_info_button"
app:layout_constraintTop_toTopOf="@+id/barrier2" />
<Button
android:id="@+id/clear_info_button"
@@ -33,11 +52,13 @@
android:layout_height="wrap_content"
android:text="@string/clear_button"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1"
app:layout_constraintTop_toTopOf="@+id/barrier2" />
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:enabled="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@@ -102,6 +123,8 @@
android:background="@android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="@+id/errors_text"
app:layout_constraintEnd_toStartOf="@+id/errors_text"
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintStart_toEndOf="@+id/sent_bytes_text"
app:layout_constraintTop_toTopOf="@+id/barrier1" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier1"
@@ -120,4 +143,10 @@
"results_text,on_ready_times_text,divider,sent_bytes_text,error_count_text"
tools:layout_editor_absoluteX="135dp"
tools:layout_editor_absoluteY="85dp" />
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/tests/CarTelemetryApp/res/raw/conn_sessions.lua b/tests/CarTelemetryApp/res/raw/conn_sessions.lua
index 1cdf685..ad84a66 100644
--- a/tests/CarTelemetryApp/res/raw/conn_sessions.lua
+++ b/tests/CarTelemetryApp/res/raw/conn_sessions.lua
@@ -22,7 +22,7 @@
if published_data['packages'] == nil then
-- on_metrics_report(r) sends r as finished result table
-- on_metrics_report(r, s) sends r as finished result table while also sending
- -- s as intermediate result that will be sent received time as 'state' param
+ -- s as intermediate result that will be received next time as 'state' param
log("packages is nil, only sessions data available.")
on_metrics_report(res)
do return end
diff --git a/tests/CarTelemetryApp/res/values/strings.xml b/tests/CarTelemetryApp/res/values/strings.xml
index 8f7258b..b213496 100644
--- a/tests/CarTelemetryApp/res/values/strings.xml
+++ b/tests/CarTelemetryApp/res/values/strings.xml
@@ -23,6 +23,8 @@
<string name="log_hint" translatable="false">Logs displayed here.</string>
<string name="clear_button" translatable="false">CLEAR</string>
<string name="history_button" translatable="false">HISTORY</string>
+ <string name="add_button" translatable="false">ADD</string>
+ <string name="remove_button" translatable="false">REMOVE</string>
<string name="results" translatable="false">Results:</string>
<string name="errors" translatable="false">Errors:</string>
<string name="showing_history" translatable="false">Showing History For:</string>
diff --git a/tests/CarTelemetryApp/res/xml/configs.xml b/tests/CarTelemetryApp/res/xml/configs.xml
index 00396dc..c4c10cd 100644
--- a/tests/CarTelemetryApp/res/xml/configs.xml
+++ b/tests/CarTelemetryApp/res/xml/configs.xml
@@ -53,22 +53,6 @@
</subscribers>
</config>
<config
- name="ethernet_with_session_metrics_config"
- version="1"
- script_name="conn_sessions">
- <subscribers>
- <subscriber
- handler="onConnectivityDataWithSession"
- priority="1">
- <publisher
- type="connectivity">
- <transport>TRANSPORT_ETHERNET</transport>
- <oem_type>OEM_NONE</oem_type>
- </publisher>
- </subscriber>
- </subscribers>
- </config>
- <config
name="cellular_with_session_metrics_config"
version="1"
script_name="conn_sessions">
@@ -84,4 +68,20 @@
</subscriber>
</subscribers>
</config>
+ <config
+ name="ethernet_with_session_metrics_config"
+ version="1"
+ script_name="conn_sessions">
+ <subscribers>
+ <subscriber
+ handler="onConnectivityDataWithSession"
+ priority="1">
+ <publisher
+ type="connectivity">
+ <transport>TRANSPORT_ETHERNET</transport>
+ <oem_type>OEM_NONE</oem_type>
+ </publisher>
+ </subscriber>
+ </subscribers>
+ </config>
</configs>
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
index e5c3087..53a300b 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarMetricsCollectorService.java
@@ -15,19 +15,27 @@
*/
package com.android.car.cartelemetryapp;
-import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Service;
import android.car.Car;
import android.car.telemetry.CarTelemetryManager;
import android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback;
import android.car.telemetry.TelemetryProto.MetricsConfig;
+import android.car.telemetry.TelemetryProto.TelemetryError;
import android.content.Intent;
-import android.os.Binder;
import android.os.IBinder;
-import android.util.Log;
+import android.os.Parcel;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
-import java.util.HashSet;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -37,15 +45,21 @@
* Service to interface with CarTelemetryManager.
*/
public class CarMetricsCollectorService extends Service {
- private static final String TAG = CarMetricsCollectorService.class.getSimpleName();
private static final String ASSETS_METRICS_CONFIG_FOLDER = "metricsconfigs";
+ private static final int HISTORY_SIZE = 10;
private final Executor mExecutor = Executors.newSingleThreadExecutor();
- private final IBinder mBinder = new ServiceBinder();
+ private final ReportListener mReportListener = new ReportListener();
+ private final ReportCallback mReportCallback = new ReportCallback();
private Car mCar;
private CarTelemetryManager mCarTelemetryManager;
- private Set<String> mActiveConfigs = new HashSet<>();
private ConfigParser mConfigParser;
private Map<String, MetricsConfig> mConfigs;
+ private Map<String, IConfigData> mConfigData = new HashMap<>();
+ private Map<String, Deque<PersistableBundle>> mBundleHistory = new HashMap<>();
+ private Map<String, Deque<String>> mErrorHistory = new HashMap<>();
+ private IConfigStateListener mConfigStateListener;
+ private IResultListener mResultListener;
+ private AddMetricsConfigCallback mAddConfigCallback = new AddConfigCallback();
private Car.CarServiceLifecycleListener mCarLifecycleListener = (car, ready) -> {
if (ready) {
mCarTelemetryManager =
@@ -53,6 +67,60 @@
}
};
+ private final ICarMetricsCollectorService.Stub mBinder =
+ new ICarMetricsCollectorService.Stub() {
+ @Override
+ public List<IConfigData> getConfigData() {
+ return new ArrayList<>(mConfigData.values());
+ }
+
+ @Override
+ public void addConfig(String configName) {
+ addMetricsConfig(configName);
+ }
+
+ @Override
+ public void removeConfig(String configName) {
+ removeMetricsConfig(configName);
+ }
+
+ @Override
+ public void setConfigStateListener(IConfigStateListener listener) {
+ mConfigStateListener = listener;
+ }
+
+ @Override
+ public void setResultListener(IResultListener listener) {
+ mResultListener = listener;
+ mCarTelemetryManager.setReportReadyListener(getMainExecutor(), mReportListener);
+ }
+
+ @Override
+ public List<PersistableBundle> getBundleHistory(String configName) {
+ return new ArrayList(mBundleHistory.get(configName));
+ }
+
+ @Override
+ public List<String> getErrorHistory(String configName) {
+ return new ArrayList(mErrorHistory.get(configName));
+ }
+
+ @Override
+ public void clearHistory(String configName) {
+ mBundleHistory.get(configName).clear();
+ mErrorHistory.get(configName).clear();
+ IConfigData configData = mConfigData.get(configName);
+ configData.onReadyTimes = 0;
+ configData.sentBytes = 0;
+ configData.errorCount = 0;
+ }
+
+ @Override
+ public String getLog() {
+ return dumpLogs();
+ }
+ };
+
@Override
public void onCreate() {
super.onCreate();
@@ -63,6 +131,7 @@
mCarLifecycleListener);
mConfigParser = new ConfigParser(this.getApplicationContext());
mConfigs = mConfigParser.getConfigs();
+ updateConfigData();
addActiveConfigs();
}
@@ -76,116 +145,158 @@
return mBinder;
}
- public class ServiceBinder extends Binder {
- CarMetricsCollectorService getService() {
- return CarMetricsCollectorService.this;
- }
- }
-
public String dumpLogs() {
return mConfigParser.dumpLogs();
}
- /**
- * Get all the config names that are in the assets folder.
- *
- * They are not necessarily active.
- */
- public String[] getAllConfigNames() {
- return mConfigs.keySet().toArray(new String[0]);
- }
-
- /**
- * Gets the finished report.
- *
- * @param configName the name of the {@link MetricsConfig} to get the report for.
- * @param executor {@link Executor} to execute the callback in.
- * @param callback function to be called with the finished report.
- */
- public void getFinishedReport(
- @NonNull String configName,
- @CallbackExecutor @NonNull Executor executor,
- @NonNull CarTelemetryManager.MetricsReportCallback callback) {
- mCarTelemetryManager.getFinishedReport(configName, executor, callback);
- }
-
- /**
- * Sets listener for getting notified when a report is ready.
- *
- * @param executor {@link Executor} to execute the listener on.
- * @param listener the callback to call when report is ready.
- */
- public void setReportReadyListener(
- @CallbackExecutor @NonNull Executor executor,
- @NonNull CarTelemetryManager.ReportReadyListener listener) {
- mCarTelemetryManager.setReportReadyListener(executor, listener);
- }
-
- /**
- * Adds {@link MetricsConfig} of a specific name.
- *
- * @param configName name of the {@link MetricsConfig} to add.
- * @param executor {@link Executor} to execute the add operation on.
- * @param callback the callback to call with the status of the add operation.
- */
- public void addMetricsConfig(
- @NonNull String configName,
- @CallbackExecutor @NonNull Executor executor,
- @NonNull AddMetricsConfigCallback callback) {
+ private void addMetricsConfig(String configName) {
if (!mConfigs.containsKey(configName)) {
throw new IllegalArgumentException(
"Failed to add metrics config, name does not exist! " + configName);
}
mCarTelemetryManager.addMetricsConfig(
- configName, mConfigs.get(configName).toByteArray(), mExecutor, callback);
+ configName, mConfigs.get(configName).toByteArray(), mExecutor, mAddConfigCallback);
}
- /**
- * Removes the named metrics config.
- */
- public void removeMetricsConfig(@NonNull String configName) {
+ private void removeMetricsConfig(String configName) {
mCarTelemetryManager.removeMetricsConfig(configName);
- }
-
- /**
- * Gets the active configs.
- *
- * @return activated configs.
- */
- public Set<String> getActiveConfigs() {
- return mActiveConfigs;
- }
-
- private void onAddMetricsConfigStatus(String metricsConfigName, int statusCode) {
- Log.i(TAG, "addMetricsConfig for " + metricsConfigName + " returned status code = "
- + addConfigStatusToString(statusCode));
- if (statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED
- || statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
- mActiveConfigs.add(metricsConfigName);
- }
+ mConfigData.get(configName).selected = false;
}
private void addActiveConfigs() {
- // TODO(b/230664179): specific logic for what configs should be added
for (String configName : mConfigs.keySet()) {
- addMetricsConfig(configName, mExecutor, this::onAddMetricsConfigStatus);
+ if (mConfigData.get(configName).selected) {
+ addMetricsConfig(configName);
+ }
}
}
- private String addConfigStatusToString(int statusCode) {
- switch (statusCode) {
- case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED:
- return "SUCCESS";
- case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS:
- return "ERROR ALREADY_EXISTS";
- case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD:
- return "ERROR VERSION_TOO_OLD";
- case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_PARSE_FAILED:
- return "ERROR PARSE_FAILED";
- case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED:
- return "ERROR SIGNATURE_VERIFICATION_FAILED";
- default:
- return "ERROR UNKNOWN";
+ /** Updates the config data mapping from the config list.
+ * If config list has newer version config, that config is either added or updated in the
+ * config data mapping and set selected.
+ */
+ private void updateConfigData() {
+ // Add new or updated config data
+ for (MetricsConfig config : mConfigs.values()) {
+ if (!mConfigData.containsKey(config.getName())
+ || mConfigData.get(config.getName()).version < config.getVersion()) {
+ IConfigData configData = new IConfigData();
+ configData.name = config.getName();
+ configData.version = config.getVersion();
+ configData.selected = true;
+ mConfigData.put(config.getName(), configData);
+ mBundleHistory.put(config.getName(), new ArrayDeque<>());
+ mErrorHistory.put(config.getName(), new ArrayDeque<>());
+ }
+ }
+ // Remove config data for configs not in mConfigs
+ Set<String> keys = mConfigData.keySet();
+ for (String name : keys) {
+ if (!mConfigs.containsKey(name)) {
+ mConfigData.remove(name);
+ mBundleHistory.remove(name);
+ mErrorHistory.remove(name);
+ }
+ }
+ }
+
+ private String errorToString(TelemetryError error) {
+ StringBuilder sb = new StringBuilder()
+ .append(":\n")
+ .append(" Error type: ")
+ .append(error.getErrorType().name())
+ .append("\n")
+ .append(" Message: ")
+ .append(error.getMessage());
+ return sb.toString();
+ }
+
+ private int getPersistableBundleByteSize(@Nullable PersistableBundle bundle) {
+ if (bundle == null) {
+ return 0;
+ }
+ Parcel parcel = Parcel.obtain();
+ parcel.writePersistableBundle(bundle);
+ int size = parcel.dataSize();
+ parcel.recycle();
+ return size;
+ }
+
+ private class ReportListener implements CarTelemetryManager.ReportReadyListener {
+ @Override
+ public void onReady(@NonNull String metricsConfigName) {
+ mCarTelemetryManager.getFinishedReport(
+ metricsConfigName, getMainExecutor(), mReportCallback);
+ }
+ }
+
+ private class ReportCallback implements CarTelemetryManager.MetricsReportCallback {
+ @Override
+ public void onResult(
+ @NonNull String metricsConfigName,
+ @Nullable PersistableBundle report,
+ @Nullable byte[] telemetryError,
+ int status) {
+ IConfigData configData = mConfigData.get(metricsConfigName);
+ String errorString = null;
+ if (report != null) {
+ if (!mBundleHistory.containsKey(metricsConfigName)) {
+ mBundleHistory.put(metricsConfigName, new ArrayDeque<>());
+ }
+ Deque<PersistableBundle> reportHistory = mBundleHistory.get(metricsConfigName);
+ if (reportHistory.size() >= HISTORY_SIZE) {
+ // Remove oldest element
+ reportHistory.pollFirst();
+ }
+ reportHistory.addLast(report);
+ configData.sentBytes += getPersistableBundleByteSize(report);
+ configData.onReadyTimes += 1;
+ }
+ if (telemetryError != null) {
+ if (!mErrorHistory.containsKey(metricsConfigName)) {
+ mErrorHistory.put(metricsConfigName, new ArrayDeque<>());
+ }
+ Deque<String> errorHistory = mErrorHistory.get(metricsConfigName);
+ if (errorHistory.size() >= HISTORY_SIZE) {
+ // Remove oldest element
+ errorHistory.pollFirst();
+ }
+ TelemetryError error;
+ try {
+ error = TelemetryError.parseFrom(telemetryError);
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalStateException(
+ "Failed to get error from bytes, invalid proto buffer.", e);
+ }
+ errorString = errorToString(error);
+ errorHistory.addLast(errorString);
+ configData.errorCount += 1;
+ }
+ try {
+ mResultListener.onResult(metricsConfigName, configData, report, errorString);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call IResultListener.onResult.", e);
+ }
+ }
+ }
+
+ private class AddConfigCallback implements AddMetricsConfigCallback {
+ @Override
+ public void onAddMetricsConfigStatus(
+ @NonNull String metricsConfigName, int statusCode) {
+ if (statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED
+ || statusCode == CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
+ mConfigData.get(metricsConfigName).selected = true;
+ if (mConfigStateListener != null) {
+ try {
+ mConfigStateListener.onConfigAdded(metricsConfigName);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call IConfigStateListener.onConfigAdded.", e);
+ }
+ }
+ }
}
}
}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
index a388924..b23961a 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/CarTelemetryActivity.java
@@ -16,25 +16,15 @@
package com.android.car.cartelemetryapp;
-import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS;
-import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.Activity;
-import android.car.telemetry.CarTelemetryManager.AddMetricsConfigCallback;
-import android.car.telemetry.CarTelemetryManager.MetricsReportCallback;
-import android.car.telemetry.CarTelemetryManager.ReportReadyListener;
-import android.car.telemetry.TelemetryProto.TelemetryError;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.Parcel;
import android.os.PersistableBundle;
-import android.util.Log;
+import android.os.RemoteException;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -48,15 +38,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.protobuf.InvalidProtocolBufferException;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InvalidClassException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
@@ -66,17 +47,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
public class CarTelemetryActivity extends Activity {
- private static final String TAG = CarTelemetryActivity.class.getSimpleName();
private static final int LOG_SIZE = 100;
- private static final String APP_DATA_FILENAME = "appdata";
- private CarMetricsCollectorService mService;
- private ReportCallback mReportCallback = new ReportCallback();
- private ReportListener mReportListener = new ReportListener();
- private String[] mConfigNames;
+ private ICarMetricsCollectorService mService;
private TextView mConfigNameView;
private TextView mHistoryView;
private TextView mLogView;
@@ -85,17 +59,17 @@
private Button mPopupCloseButton;
private Button mConfigButton;
private ConfigListAdaptor mAdapter;
- private List<ConfigData> mConfigList = new ArrayList<>();
+ private List<IConfigData> mConfigData = new ArrayList<>();
private Map<String, Integer> mConfigNameIndex = new HashMap<>();
private Deque<String> mLogs = new ArrayDeque<>();
+ private Map<String, List<PersistableBundle>> mBundleHistory = new HashMap<>();
+ private Map<String, List<String>> mErrorHistory = new HashMap<>();
private boolean mDataRadioSelected = true;
- private ConfigData mSelectedInfoConfig = new ConfigData("");
+ private IConfigData mSelectedInfoConfig = new IConfigData();
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
- CarMetricsCollectorService.ServiceBinder binder =
- (CarMetricsCollectorService.ServiceBinder) service;
- mService = binder.getService();
+ mService = ICarMetricsCollectorService.Stub.asInterface(service);
onServiceBound();
}
@@ -115,19 +89,19 @@
RadioButton dataRadio = findViewById(R.id.data_radio);
dataRadio.setOnClickListener(v -> {
mDataRadioSelected = true;
- mHistoryView.setText(mSelectedInfoConfig.getBundleHistoryString());
+ mHistoryView.setText(getBundleHistoryString(mSelectedInfoConfig.name));
});
RadioButton errorRadio = findViewById(R.id.error_radio);
errorRadio.setOnClickListener(v -> {
mDataRadioSelected = false;
- mHistoryView.setText(mSelectedInfoConfig.getErrorHistoryString());
+ mHistoryView.setText(getErrorHistoryString(mSelectedInfoConfig.name));
});
ViewGroup parent = findViewById(R.id.mainLayout);
View configsView = this.getLayoutInflater().inflate(R.layout.config_popup, parent, false);
mConfigPopup = new PopupWindow(
- configsView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ configsView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mConfigButton = findViewById(R.id.config_button);
mConfigButton.setOnClickListener(v -> {
mConfigPopup.showAtLocation(configsView, Gravity.CENTER, 0, 0);
@@ -155,221 +129,232 @@
}
private void onServiceBound() {
- mConfigNames = mService.getAllConfigNames();
- addToLog(mService.dumpLogs());
- Set<String> mActiveConfigs = mService.getActiveConfigs();
- for (int i = 0; i < mConfigNames.length; i++) {
- mConfigNameIndex.put(mConfigNames[i], i);
+ try {
+ printLog(mService.getLog());
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.getLog.", e);
}
- Map<String, ConfigData> pastConfigMap = readAppData();
- for (String name : mConfigNames) {
- ConfigData config;
- if (pastConfigMap != null && pastConfigMap.containsKey(name)) {
- // Preserve previous state for old config
- config = pastConfigMap.get(name);
- } else {
- // New config
- config = new ConfigData(name);
+ IConfigStateListener configStateListener = new IConfigStateListener.Stub() {
+ @Override
+ public void onConfigAdded(String configName) {
+ // Set config to checked
+ mConfigData.get(mConfigNameIndex.get(configName)).selected = true;
+ getMainExecutor().execute(() -> {
+ mAdapter.notifyItemChanged(mConfigNameIndex.get(configName));
+ });
+ printLog("Added config " + configName);
}
- config.selected = mActiveConfigs.contains(name);
- mConfigList.add(config);
+ };
+ try {
+ mService.setConfigStateListener(configStateListener);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.setConfigStateListener.", e);
}
- if (mConfigList.size() != 0) {
- mSelectedInfoConfig = mConfigList.get(0); // Default to display first config data
+ IResultListener resultListener = new IResultListener.Stub() {
+ @Override
+ public void onResult(
+ String metricsConfigName,
+ IConfigData configData,
+ PersistableBundle report,
+ String telemetryError) {
+ lazyInitHistories(metricsConfigName);
+ mConfigData.set(mConfigNameIndex.get(metricsConfigName), configData);
+ // Add to bundle and error histories
+ if (report != null) {
+ if (!mBundleHistory.containsKey(metricsConfigName)) {
+ mBundleHistory.put(metricsConfigName, new ArrayList<PersistableBundle>());
+ }
+ mBundleHistory.get(metricsConfigName).add(report);
+ printLog("Received report for " + metricsConfigName);
+ } else {
+ if (!mErrorHistory.containsKey(metricsConfigName)) {
+ mErrorHistory.put(metricsConfigName, new ArrayList<String>());
+ }
+ mErrorHistory.get(metricsConfigName).add(telemetryError);
+ printLog("Received error for " + metricsConfigName);
+ }
+ if (metricsConfigName.equals(mSelectedInfoConfig.name)) {
+ refreshHistory();
+ }
+ }
+ };
+ try {
+ mService.setResultListener(resultListener);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.setResultListener.", e);
+ }
+
+ try {
+ mConfigData = mService.getConfigData();
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.getConfigData.", e);
+ }
+
+ for (int i = 0; i < mConfigData.size(); i++) {
+ mConfigNameIndex.put(mConfigData.get(i).name, i);
+ }
+ if (mConfigData.size() != 0) {
+ mSelectedInfoConfig = mConfigData.get(0); // Default to display first config data
refreshHistory();
}
mAdapter = new ConfigListAdaptor(
- mConfigList, new AdaptorCallback());
+ mConfigData, new AdaptorCallback());
mRecyclerView.setAdapter(mAdapter);
-
- mService.setReportReadyListener(getMainExecutor(), mReportListener);
}
- /** Calculates the PersistableBundle byte size. */
- private int getPersistableBundleByteSize(@Nullable PersistableBundle bundle) {
- if (bundle == null) {
- return 0;
+ /** Converts bundle to string. */
+ private String bundleToString(PersistableBundle bundle) {
+ StringBuilder sb = new StringBuilder();
+ for (String key : bundle.keySet()) {
+ sb.append("--")
+ .append(key)
+ .append(": ")
+ .append(bundle.get(key).toString())
+ .append("\n");
}
- Parcel parcel = Parcel.obtain();
- parcel.writePersistableBundle(bundle);
- int size = parcel.dataSize();
- parcel.recycle();
- return size;
+ return sb.toString();
}
- /** Parses byte array to TelemetryError. */
- @Nullable
- private TelemetryError getErrorFromBytes(byte[] bytes) {
- TelemetryError error = null;
+ /** Converts bundle history to string. */
+ private String getBundleHistoryString(String configName) {
+ StringBuilder sb = new StringBuilder();
+ if (!mBundleHistory.containsKey(configName)) {
+ return "";
+ }
+ for (PersistableBundle bundle : mBundleHistory.get(configName)) {
+ sb.append(bundleToString(bundle)).append("\n");
+ }
+ return sb.toString();
+ }
+
+ /** Converts error history to string. */
+ private String getErrorHistoryString(String configName) {
+ StringBuilder sb = new StringBuilder();
+ if (!mErrorHistory.containsKey(configName)) {
+ return "";
+ }
+ for (String error : mErrorHistory.get(configName)) {
+ sb.append(error).append("\n");
+ }
+ return sb.toString();
+ }
+
+ /** Refreshes the history view with the currently selected config's data. */
+ private void refreshHistory() {
+ getMainExecutor().execute(() -> {
+ mConfigNameView.setText(mSelectedInfoConfig.name);
+ if (mDataRadioSelected) {
+ mHistoryView.setText(getBundleHistoryString(mSelectedInfoConfig.name));
+ } else {
+ mHistoryView.setText(getErrorHistoryString(mSelectedInfoConfig.name));
+ }
+ });
+ }
+
+ /** Clears the config data and histories. Cleared on server side too. */
+ private void clearConfigData(IConfigData configData) {
+ configData.onReadyTimes = 0;
+ configData.sentBytes = 0;
+ configData.errorCount = 0;
+ if (mBundleHistory.containsKey(configData.name)) {
+ mBundleHistory.get(configData.name).clear();
+ }
+ if (mErrorHistory.containsKey(configData.name)) {
+ mErrorHistory.get(configData.name).clear();
+ }
try {
- error = TelemetryError.parseFrom(bytes);
- } catch (InvalidProtocolBufferException e) {
+ mService.clearHistory(configData.name);
+ } catch (RemoteException e) {
throw new IllegalStateException(
- "Failed to get error from bytes, invalid proto buffer.", e);
- }
- return error;
- }
-
- private void writeAppData() {
- Map<String, ConfigData> configMap = new HashMap<>();
- for (ConfigData config : mConfigList) {
- configMap.put(config.getName(), config);
- }
- try (FileOutputStream fos =
- this.openFileOutput(APP_DATA_FILENAME, Context.MODE_PRIVATE);
- ObjectOutputStream oos = new ObjectOutputStream(fos)) {
- oos.writeObject(configMap);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to write app data to file.", e);
+ "Failed to ICarMetricsCollectorService.clearHistory.", e);
}
}
- private Map<String, ConfigData> readAppData() {
- try (FileInputStream fis = this.openFileInput(APP_DATA_FILENAME);
- ObjectInputStream ois = new ObjectInputStream(fis)) {
- return (HashMap<String, ConfigData>) ois.readObject();
- } catch (FileNotFoundException | InvalidClassException e) {
- // File might not have been created yet or object definition changed
- Log.w(TAG, "Could not read app data. Does not exist or format changed.", e);
- return null;
- } catch (IOException | ClassNotFoundException e) {
- throw new IllegalStateException("Failed to read app data from file.", e);
+ /** Retrieves histories from service if not already present. */
+ private void lazyInitHistories(String configName) {
+ if (!mBundleHistory.containsKey(configName)) {
+ try {
+ mBundleHistory.put(configName, mService.getBundleHistory(configName));
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.getBundleHistory.", e);
+ }
+ }
+ if (!mErrorHistory.containsKey(configName)) {
+ try {
+ mErrorHistory.put(configName, mService.getErrorHistory(configName));
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to call ICarMetricsCollectorService.getErrorHistory.", e);
+ }
}
}
- private void addToLog(String log) {
- // Add to logs, only a set number is kept
+ /** Prints to log view the log with prefixed timestamp. */
+ private void printLog(String log) {
+ String text = LocalDateTime.now(ZoneId.systemDefault())
+ .format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) + ": " + log;
if (mLogs.size() >= LOG_SIZE) {
- // Remove the oldest
+ // Remove oldest element
mLogs.pollLast();
}
- mLogs.addFirst(log);
- // Display log
- mLogView.setText(String.join("\n", mLogs));
- }
-
- private void refreshHistory() {
- mConfigNameView.setText(mSelectedInfoConfig.getName());
- if (mDataRadioSelected) {
- mHistoryView.setText(mSelectedInfoConfig.getBundleHistoryString());
- } else {
- mHistoryView.setText(mSelectedInfoConfig.getErrorHistoryString());
- }
- }
-
- /** Listener for getting notified of ready reports. */
- private class ReportListener implements ReportReadyListener {
- @Override
- public void onReady(@NonNull String metricsConfigName) {
- mService.getFinishedReport(metricsConfigName, getMainExecutor(), mReportCallback);
- }
- }
-
- /** Callback when report is retrieved. */
- private class ReportCallback implements MetricsReportCallback {
- @Override
- public void onResult(
- @NonNull String metricsConfigName,
- @Nullable PersistableBundle report,
- @Nullable byte[] telemetryError,
- int status) {
- int index = mConfigNameIndex.get(metricsConfigName);
- ConfigData config = mConfigList.get(index);
- StringBuilder sb = new StringBuilder();
- sb.append(LocalDateTime.now(ZoneId.systemDefault())
- .format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
- .append(": ");
- if (report != null) {
- sb.append("Received Report - ");
- config.onReadyTimes += 1;
- config.sentBytes += getPersistableBundleByteSize(report);
- if (report != null) {
- // Add to bundle history
- config.addBundle(LocalDateTime.now(ZoneId.systemDefault()), report);
- }
- } else if (telemetryError != null) {
- sb.append("Received Error - ");
- config.errorCount += 1;
- TelemetryError error = getErrorFromBytes(telemetryError);
- if (error != null) {
- // Add to error history
- config.addError(LocalDateTime.now(ZoneId.systemDefault()), error);
- }
- }
- sb.append(metricsConfigName);
- mAdapter.notifyItemChanged(index);
- addToLog(sb.toString());
- writeAppData();
- refreshHistory();
- }
+ mLogs.addFirst(text);
+ getMainExecutor().execute(() -> {
+ mLogView.setText(String.join("\n", mLogs));
+ });
}
private class AdaptorCallback implements ConfigListAdaptor.Callback {
@Override
- public void onCheckedChanged(ConfigData config, boolean isChecked) {
- int index = mConfigNameIndex.get(config.getName());
- if (isChecked) {
- mService.addMetricsConfig(
- config.getName(),
- getMainExecutor(),
- new AddConfigCallback(config, mAdapter, index, getMainExecutor()));
- } else {
- mService.removeMetricsConfig(config.getName());
- config.selected = false;
- getMainExecutor().execute(() -> {
- mAdapter.notifyItemChanged(index);
- writeAppData();
- });
+ public void onAddButtonClicked(IConfigData configData) {
+ try {
+ mService.addConfig(configData.name);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to ICarMetricsCollectorService.addConfig.", e);
}
}
@Override
- public void onInfoButtonClicked(ConfigData config) {
- mSelectedInfoConfig = config;
- mConfigNameView.setText(config.getName());
- if (mDataRadioSelected) {
- mHistoryView.setText(config.getBundleHistoryString());
- } else {
- mHistoryView.setText(config.getErrorHistoryString());
+ public void onRemoveButtonClicked(IConfigData configData) {
+ try {
+ mService.removeConfig(configData.name);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Failed to ICarMetricsCollectorService.removeConfig.", e);
}
- }
-
- @Override
- public void onClearButtonClicked(ConfigData config) {
- int index = mConfigNameIndex.get(config.getName());
- config.clearHistory();
+ configData.selected = false;
getMainExecutor().execute(() -> {
- mAdapter.notifyItemChanged(index);
- writeAppData();
+ mAdapter.notifyItemChanged(mConfigNameIndex.get(configData.name));
+ });
+ printLog("Removed config " + configData.name);
+ }
+
+ @Override
+ public void onInfoButtonClicked(IConfigData configData) {
+ mSelectedInfoConfig = configData;
+ mConfigNameView.setText(configData.name);
+ lazyInitHistories(configData.name);
+ getMainExecutor().execute(() -> {
+ if (mDataRadioSelected) {
+ mHistoryView.setText(getBundleHistoryString(configData.name));
+ } else {
+ mHistoryView.setText(getErrorHistoryString(configData.name));
+ }
});
}
- }
- private class AddConfigCallback implements AddMetricsConfigCallback {
- private ConfigData mConfig;
- private ConfigListAdaptor mAdaptor;
- private int mIndex;
- private Executor mExecutor;
- AddConfigCallback(
- ConfigData config, ConfigListAdaptor adaptor, int index, Executor executor) {
- mConfig = config;
- mAdaptor = adaptor;
- mIndex = index;
- mExecutor = executor;
- }
@Override
- public void onAddMetricsConfigStatus(
- @NonNull String metricsConfigName, int statusCode) {
- if (statusCode == STATUS_ADD_METRICS_CONFIG_SUCCEEDED
- || statusCode == STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS) {
- mConfig.selected = true;
- } else {
- mConfig.selected = false;
- }
- mExecutor.execute(() -> {
- mAdaptor.notifyItemChanged(mIndex);
- writeAppData();
+ public void onClearButtonClicked(IConfigData configData) {
+ int index = mConfigNameIndex.get(configData.name);
+ clearConfigData(configData);
+ getMainExecutor().execute(() -> {
+ mAdapter.notifyItemChanged(index);
});
}
}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java
deleted file mode 100644
index c9c27b3..0000000
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigData.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2022 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.cartelemetryapp;
-
-import android.car.telemetry.TelemetryProto.TelemetryError;
-import android.os.PersistableBundle;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayDeque;
-import java.util.Deque;
-
-/** Class for keeping config data. */
-public class ConfigData implements Serializable {
- public boolean selected = true;
- public int onReadyTimes = 0;
- public int sentBytes = 0;
- public int errorCount = 0;
- private String mName;
- private Deque<BundleHistory> mBundleHistory = new ArrayDeque<>();
- private Deque<ErrorHistory> mErrorHistory = new ArrayDeque<>();
- private static final int HISTORY_SIZE = 10;
-
- ConfigData(String name) {
- mName = name;
- }
-
- /*
- * Gets the config name.
- */
- public String getName() {
- return mName;
- }
-
- /*
- * Adds a bundle to the bundles history deque.
- *
- * Newest entry is added to the front while oldest are a the end.
- * Only a limited number of entries are kept.
- *
- * @param time timestamp of the bundle.
- * @param bundle the {@link PersistableBundle} to be saved as history.
- */
- public void addBundle(LocalDateTime time, PersistableBundle bundle) {
- if (mBundleHistory.size() >= HISTORY_SIZE) {
- // Remove oldest element
- mBundleHistory.pollLast();
- }
- mBundleHistory.addFirst(new BundleHistory(time, bundle));
- }
-
- /**
- * Clears all of configs history.
- */
- public void clearHistory() {
- onReadyTimes = 0;
- sentBytes = 0;
- errorCount = 0;
- mBundleHistory.clear();
- mErrorHistory.clear();
- }
-
- /*
- * Adds an error data to the bundles errors deque.
- *
- * Newest entry is added to the front while oldest are a the end.
- * Only a limited number of entries are kept.
- *
- * @param time timestamp of the error.
- * @param error the {@link TelemetryError} to be saved as history.
- */
- public void addError(LocalDateTime time, TelemetryError error) {
- if (mErrorHistory.size() >= HISTORY_SIZE) {
- // Remove oldest element
- mErrorHistory.pollLast();
- }
- mErrorHistory.addFirst(new ErrorHistory(time, error));
- }
-
- /*
- * Gets the string representation of the bundle history.
- *
- * @return string of the saved bundles history.
- */
- public String getBundleHistoryString() {
- StringBuilder sb = new StringBuilder();
- for (BundleHistory bh : mBundleHistory) {
- sb.append(bh.getString()).append("\n");
- }
- return sb.toString();
- }
-
- /*
- * Gets the string representation of the error history.
- *
- * @return string of the saved error history.
- */
- public String getErrorHistoryString() {
- StringBuilder sb = new StringBuilder();
- for (ErrorHistory eh : mErrorHistory) {
- sb.append(eh.getString()).append("\n");
- }
- return sb.toString();
- }
-
- private static class BundleHistory implements Serializable {
- private LocalDateTime mTime;
- private transient PersistableBundle mBundle;
-
- BundleHistory(LocalDateTime t, PersistableBundle b) {
- mTime = t;
- mBundle = b;
- }
-
- LocalDateTime getTime() {
- return mTime;
- }
-
- PersistableBundle getBundle() {
- return mBundle;
- }
-
- String getString() {
- StringBuilder sb = new StringBuilder()
- .append(mTime.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
- .append(":\n");
- for (String key : mBundle.keySet()) {
- sb.append(" ")
- .append(key)
- .append(": ")
- .append(mBundle.get(key).toString())
- .append("\n");
- }
- return sb.toString();
- }
-
- private void writeObject(ObjectOutputStream oos) throws IOException {
- oos.defaultWriteObject();
- mBundle.writeToStream(oos);
- }
-
- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
- ois.defaultReadObject();
- mBundle = PersistableBundle.readFromStream(ois);
- }
- }
-
- private static class ErrorHistory implements Serializable {
- private LocalDateTime mTime;
- private transient TelemetryError mError;
-
- ErrorHistory(LocalDateTime t, TelemetryError e) {
- mTime = t;
- mError = e;
- }
-
- LocalDateTime getTime() {
- return mTime;
- }
-
- TelemetryError getError() {
- return mError;
- }
-
- String getString() {
- StringBuilder sb = new StringBuilder()
- .append(mTime.format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))
- .append(":\n")
- .append(" Error type: ")
- .append(mError.getErrorType().name())
- .append("\n")
- .append(" Message: ")
- .append(mError.getMessage());
- return sb.toString();
- }
-
- private void writeObject(ObjectOutputStream oos) throws IOException {
- oos.defaultWriteObject();
- mError.writeTo(oos);
- }
-
- private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
- ois.defaultReadObject();
- mError = TelemetryError.parseFrom(ois);
- }
- }
-}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
index 8a90a69..b43db7e 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigListAdaptor.java
@@ -29,66 +29,43 @@
import java.util.List;
public class ConfigListAdaptor extends RecyclerView.Adapter<ConfigListAdaptor.ViewHolder> {
- private List<ConfigData> mConfigs;
+ private List<IConfigData> mConfigs;
private Callback mCallback;
public interface Callback {
- void onCheckedChanged(ConfigData config, boolean isChecked);
- void onInfoButtonClicked(ConfigData config);
- void onClearButtonClicked(ConfigData config);
+ void onAddButtonClicked(IConfigData config);
+ void onRemoveButtonClicked(IConfigData config);
+ void onInfoButtonClicked(IConfigData config);
+ void onClearButtonClicked(IConfigData config);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
- private final CheckBox mCheckBox;
- private final TextView mConfigText;
- private final TextView mOnReadyText;
- private final TextView mSentBytesText;
- private final TextView mErrorsCountText;
- private final Button mInfoButton;
- private final Button mClearButton;
+ public final CheckBox checkBox;
+ public final TextView configText;
+ public final TextView onReadyText;
+ public final TextView sentBytesText;
+ public final TextView errorsCountText;
+ public final Button addConfigButton;
+ public final Button removeConfigButton;
+ public final Button infoButton;
+ public final Button clearButton;
public ViewHolder(View view) {
super(view);
- mCheckBox = view.findViewById(R.id.checkbox);
- mConfigText = view.findViewById(R.id.config_name_text);
- mOnReadyText = view.findViewById(R.id.on_ready_times_text);
- mSentBytesText = view.findViewById(R.id.sent_bytes_text);
- mErrorsCountText = view.findViewById(R.id.error_count_text);
- mInfoButton = view.findViewById(R.id.show_info_button);
- mClearButton = view.findViewById(R.id.clear_info_button);
- }
-
- public CheckBox getCheckBox() {
- return mCheckBox;
- }
-
- public TextView getConfigText() {
- return mConfigText;
- }
-
- public TextView getOnReadyText() {
- return mOnReadyText;
- }
-
- public TextView getSentBytesText() {
- return mSentBytesText;
- }
-
- public TextView getErrorsCountText() {
- return mErrorsCountText;
- }
-
- public Button getInfoButton() {
- return mInfoButton;
- }
-
- public Button getClearButton() {
- return mClearButton;
+ checkBox = view.findViewById(R.id.checkbox);
+ configText = view.findViewById(R.id.config_name_text);
+ onReadyText = view.findViewById(R.id.on_ready_times_text);
+ sentBytesText = view.findViewById(R.id.sent_bytes_text);
+ errorsCountText = view.findViewById(R.id.error_count_text);
+ addConfigButton = view.findViewById(R.id.add_config_button);
+ removeConfigButton = view.findViewById(R.id.remove_config_button);
+ infoButton = view.findViewById(R.id.show_info_button);
+ clearButton = view.findViewById(R.id.clear_info_button);
}
}
public ConfigListAdaptor(
- List<ConfigData> configs,
+ List<IConfigData> configs,
Callback callback) {
mConfigs = configs;
mCallback = callback;
@@ -105,20 +82,23 @@
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
int pos = holder.getAbsoluteAdapterPosition();
- ConfigData config = mConfigs.get(pos);
- holder.getConfigText().setText(config.getName());
- holder.getCheckBox().setOnCheckedChangeListener((buttonView, isChecked) -> {
- mCallback.onCheckedChanged(config, isChecked);
- });
- holder.getCheckBox().setChecked(config.selected);
- holder.getOnReadyText().setText(String.valueOf(config.onReadyTimes));
+ IConfigData config = mConfigs.get(pos);
+ holder.checkBox.setChecked(config.selected);
+ holder.configText.setText(config.name);
+ holder.onReadyText.setText(String.valueOf(config.onReadyTimes));
String bytesSentStr = String.valueOf(config.sentBytes) + " B";
- holder.getSentBytesText().setText(bytesSentStr);
- holder.getErrorsCountText().setText(String.valueOf(config.errorCount));
- holder.getInfoButton().setOnClickListener(v -> {
+ holder.sentBytesText.setText(bytesSentStr);
+ holder.errorsCountText.setText(String.valueOf(config.errorCount));
+ holder.addConfigButton.setOnClickListener(v -> {
+ mCallback.onAddButtonClicked(config);
+ });
+ holder.removeConfigButton.setOnClickListener(v -> {
+ mCallback.onRemoveButtonClicked(config);
+ });
+ holder.infoButton.setOnClickListener(v -> {
mCallback.onInfoButtonClicked(config);
});
- holder.getClearButton().setOnClickListener(v -> {
+ holder.clearButton.setOnClickListener(v -> {
mCallback.onClearButtonClicked(config);
});
}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
index cd97210..870b7b0 100644
--- a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ConfigParser.java
@@ -118,6 +118,7 @@
log("Error parsing XML file! " + parser.getPositionDescription()
+ " Error: " + e.getMessage());
}
+ log("Finished parsing configs: " + configs.size());
return configs;
}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl
new file mode 100644
index 0000000..9cd2aba
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/ICarMetricsCollectorService.aidl
@@ -0,0 +1,20 @@
+package com.android.car.cartelemetryapp;
+
+import android.os.PersistableBundle;
+import com.android.car.cartelemetryapp.IConfigData;
+import com.android.car.cartelemetryapp.IConfigStateListener;
+import com.android.car.cartelemetryapp.IResultListener;
+
+import java.util.List;
+
+interface ICarMetricsCollectorService {
+ List<IConfigData> getConfigData();
+ void addConfig(in String configName);
+ void removeConfig(in String configName);
+ void setConfigStateListener(in IConfigStateListener listener);
+ void setResultListener(in IResultListener listener);
+ List<PersistableBundle> getBundleHistory(in String configName);
+ List<String> getErrorHistory(in String configName);
+ void clearHistory(in String configName);
+ String getLog();
+}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl
new file mode 100644
index 0000000..db3dbf6
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigData.aidl
@@ -0,0 +1,10 @@
+package com.android.car.cartelemetryapp;
+
+parcelable IConfigData {
+ boolean selected;
+ int onReadyTimes;
+ int sentBytes;
+ int errorCount;
+ int version;
+ String name;
+}
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl
new file mode 100644
index 0000000..b3172d9
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IConfigStateListener.aidl
@@ -0,0 +1,5 @@
+package com.android.car.cartelemetryapp;
+
+interface IConfigStateListener {
+ void onConfigAdded(in String configName);
+}
\ No newline at end of file
diff --git a/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl
new file mode 100644
index 0000000..7725e4a
--- /dev/null
+++ b/tests/CarTelemetryApp/src/com/android/car/cartelemetryapp/IResultListener.aidl
@@ -0,0 +1,12 @@
+package com.android.car.cartelemetryapp;
+
+import android.os.PersistableBundle;
+import com.android.car.cartelemetryapp.IConfigData;
+
+interface IResultListener {
+ void onResult(
+ in String metricsConfigName,
+ in IConfigData configData,
+ in PersistableBundle report,
+ in String telemetryError);
+}
\ No newline at end of file
diff --git a/tests/DiagnosticTools/res/values-en-rCA/strings.xml b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
index 4833f5f..bd4ccb9 100644
--- a/tests/DiagnosticTools/res/values-en-rCA/strings.xml
+++ b/tests/DiagnosticTools/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display Freeze Frame Info"</string>
+ <string name="display_freeze_frame_info" msgid="1425573367248263107">"Display freeze frame Info"</string>
</resources>
diff --git a/tests/DiagnosticTools/res/values-ro/strings.xml b/tests/DiagnosticTools/res/values-ro/strings.xml
index 014f068..d06e299 100644
--- a/tests/DiagnosticTools/res/values-ro/strings.xml
+++ b/tests/DiagnosticTools/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișează informații despre cadrul blocat"</string>
+ <string name="display_freeze_frame_info" msgid="1425573367248263107">"Afișați informații despre cadrul blocat"</string>
</resources>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
index 2a5d05f..8340a55 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/car_telemetry_test.xml
@@ -364,6 +364,31 @@
android:layout_height="wrap_content"
android:text="@string/get_report"/>
</LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/process_memory_snapshot_config"/>
+ <Button
+ android:id="@+id/send_on_process_memory_snapshot_config"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/add_metrics_config"/>
+ <Button
+ android:id="@+id/remove_on_process_memory_snapshot_config"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/remove_metrics_config"/>
+ <Button
+ android:id="@+id/get_on_process_memory_snapshot_report"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/get_report"/>
+ </LinearLayout>
</LinearLayout> <!-- @+id/metrics_config_buttons -->
<TextView
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 841e2ff..054a784 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -387,7 +387,7 @@
<!-- CarTelemetryService Test -->
<string name="gear_change_config" translatable="false">on_gear_change:</string>
- <string name="process_memory_config" translatable="false">process_memory:</string>
+ <string name="process_memory_config" translatable="false">process_memory_state:</string>
<string name="app_start_memory_state_captured_config" translatable="false">app_start_memory_state_captured:</string>
<string name="activity_foreground_state_changed_config" translatable="false">activity_foreground_state_changed:</string>
<string name="process_cpu_time_config" translatable="false">process_cpu_time:</string>
@@ -397,6 +397,7 @@
<string name="wifi_netstats_config" translatable="false">wifi_netstats_top_consumers:</string>
<string name="stats_and_connectivity_config" translatable="false">stats and connectivity:</string>
<string name="memory_config" translatable="false">memory:</string>
+ <string name="process_memory_snapshot_config" translatable="false">process_memory_snapshot:</string>
<string name="add_metrics_config" translatable="false">Add MetricsConfig</string>
<string name="remove_metrics_config" translatable="false">Remove MetricsConfig</string>
<string name="download_data" translatable="false">Download Data</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
index 15a9513..40a965f 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/telemetry/CarTelemetryTestFragment.java
@@ -21,6 +21,7 @@
import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_CRASH_OCCURRED;
import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED;
import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_CPU_TIME;
+import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_SNAPSHOT;
import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.WTF_OCCURRED;
@@ -69,8 +70,12 @@
/** Vehicle property via gear change section. */
private static final String LUA_SCRIPT_ON_GEAR_CHANGE =
"function onGearChange(published_data, state)\n"
- + " result = {data = \"Hello World!\"}\n"
- + " on_script_finished(result)\n"
+ + " t = {}\n"
+ + " for k, v in ipairs(published_data) do\n"
+ + " t['#' .. k] = 'Gear: ' .. v['intVal'] \n"
+ + " log(v[\"intVal\"])\n"
+ + " end\n"
+ + " on_metrics_report(t)\n"
+ "end\n";
private static final TelemetryProto.Publisher VEHICLE_PROPERTY_PUBLISHER =
@@ -90,7 +95,7 @@
TelemetryProto.Subscriber.newBuilder()
.setHandler("onGearChange")
.setPublisher(VEHICLE_PROPERTY_PUBLISHER)
- .setPriority(SCRIPT_EXECUTION_PRIORITY_LOW))
+ .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
.build();
private static final String ON_GEAR_CHANGE_CONFIG_NAME =
METRICS_CONFIG_ON_GEAR_CHANGE_V1.getName();
@@ -98,8 +103,8 @@
/** ProcessMemoryState section. */
private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_STATE = new StringBuilder()
.append("function calculateAverage(tbl)\n")
- .append(" sum = 0\n")
- .append(" size = 0\n")
+ .append(" local sum = 0\n")
+ .append(" local size = 0\n")
.append(" for _, value in ipairs(tbl) do\n")
.append(" sum = sum + value\n")
.append(" size = size + 1\n")
@@ -107,7 +112,7 @@
.append(" return sum/size\n")
.append("end\n")
.append("function onProcessMemory(published_data, state)\n")
- .append(" result = {}\n")
+ .append(" local result = {}\n")
.append(" result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
.append(" result.major_page_fault_avg = calculateAverage("
+ "published_data.page_major_fault)\n")
@@ -145,8 +150,8 @@
/** AppStartMemoryStateCaptured section. */
private static final String LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED = new StringBuilder()
.append("function calculateAverage(tbl)\n")
- .append(" sum = 0\n")
- .append(" size = 0\n")
+ .append(" local sum = 0\n")
+ .append(" local size = 0\n")
.append(" for _, value in ipairs(tbl) do\n")
.append(" sum = sum + value\n")
.append(" size = size + 1\n")
@@ -154,7 +159,7 @@
.append(" return sum/size\n")
.append("end\n")
.append("function onAppStartMemoryStateCaptured(published_data, state)\n")
- .append(" result = {}\n")
+ .append(" local result = {}\n")
.append(" result.uid = published_data.uid\n")
.append(" result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
.append(" result.major_page_fault_avg = calculateAverage("
@@ -192,8 +197,8 @@
private static final String LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED =
new StringBuilder()
.append("function onActivityForegroundStateChanged(published_data, state)\n")
- .append(" result = {}\n")
- .append(" n = 0\n")
+ .append(" local result = {}\n")
+ .append(" local n = 0\n")
.append(" for k, v in pairs(published_data) do\n")
.append(" result[k] = v[1]\n")
.append(" n = n + 1\n")
@@ -227,8 +232,8 @@
private static final String LUA_SCRIPT_ON_PROCESS_CPU_TIME =
new StringBuilder()
.append("function onProcessCpuTime(published_data, state)\n")
- .append(" result = {}\n")
- .append(" n = 0\n")
+ .append(" local result = {}\n")
+ .append(" local n = 0\n")
.append(" for k, v in pairs(published_data) do\n")
.append(" result[k] = v[1]\n")
.append(" n = n + 1\n")
@@ -262,7 +267,7 @@
private static final String LUA_SCRIPT_ON_APP_CRASH_OCCURRED =
new StringBuilder()
.append("function onAppCrashOccurred(published_data, state)\n")
- .append(" result = {}\n")
+ .append(" local result = {}\n")
.append(" for k, v in pairs(published_data) do\n")
.append(" result[k] = v[1]\n")
.append(" end\n")
@@ -294,7 +299,7 @@
private static final String LUA_SCRIPT_ON_ANR_OCCURRED =
new StringBuilder()
.append("function onAnrOccurred(published_data, state)\n")
- .append(" result = {}\n")
+ .append(" local result = {}\n")
.append(" for k, v in pairs(published_data) do\n")
.append(" result[k] = v[1]\n")
.append(" end\n")
@@ -325,7 +330,7 @@
private static final String LUA_SCRIPT_ON_WTF_OCCURRED =
new StringBuilder()
.append("function onWtfOccurred(published_data, state)\n")
- .append(" result = {}\n")
+ .append(" local result = {}\n")
.append(" for k, v in pairs(published_data) do\n")
.append(" result[k] = v[1]\n")
.append(" end\n")
@@ -427,15 +432,13 @@
.append(" iterations = 0\n")
.append(" end\n")
.append(" state['iterations'] = iterations + 1\n")
- .append(" report = {}\n")
- .append(" local ts_key = 'timestamp_' .. iterations\n")
- .append(" report[ts_key] = published_data['timestamp']\n")
.append(" local meminfo = published_data['meminfo']\n")
.append(" local available_memory = string.match(meminfo, "
+ "'.*MemAvailable:%s*(%d+).*')\n")
.append(" local mem_key = 'available_memory_' .. iterations\n")
- .append(" report[mem_key] = available_memory\n")
- .append(" on_metrics_report(report, state)\n")
+ .append(" published_data[mem_key] = available_memory\n")
+ .append(" published_data['meminfo'] = nil\n")
+ .append(" on_metrics_report(published_data, state)\n")
.append("end\n")
.toString();
private static final TelemetryProto.Publisher MEMORY_PUBLISHER =
@@ -445,6 +448,8 @@
.setReadIntervalSec(3)
.setMaxSnapshots(3)
.setMaxPendingTasks(10)
+ .addPackageNames("com.android.car")
+ .addPackageNames("com.android.car.scriptexecutor")
.build())
.build();
private static final TelemetryProto.MetricsConfig METRICS_CONFIG_MEMORY_V1 =
@@ -461,6 +466,32 @@
private static final String MEMORY_CONFIG_NAME =
METRICS_CONFIG_MEMORY_V1.getName();
+ /** ProcessMemorySnapshot section. */
+ private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT = new StringBuilder()
+ .append("function onProcessMemorySnapshot(published_data, state)\n")
+ .append(" on_script_finished(published_data)\n")
+ .append("end\n")
+ .toString();
+ private static final TelemetryProto.Publisher PROCESS_MEMORY_SNAPSHOT_PUBLISHER =
+ TelemetryProto.Publisher.newBuilder()
+ .setStats(
+ TelemetryProto.StatsPublisher.newBuilder()
+ .setSystemMetric(PROCESS_MEMORY_SNAPSHOT))
+ .build();
+ private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1 =
+ TelemetryProto.MetricsConfig.newBuilder()
+ .setName("process_memory_snapshot_metrics_config")
+ .setVersion(1)
+ .setScript(LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT)
+ .addSubscribers(
+ TelemetryProto.Subscriber.newBuilder()
+ .setHandler("onProcessMemorySnapshot")
+ .setPublisher(PROCESS_MEMORY_SNAPSHOT_PUBLISHER)
+ .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
+ .build();
+ private static final String PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME =
+ METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.getName();
+
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private boolean mReceiveReportNotification = false;
@@ -588,6 +619,13 @@
.setOnClickListener(this::onRemoveMemoryConfigBtnClick);
view.findViewById(R.id.get_memory_report)
.setOnClickListener(this::onGetMemoryReportBtnClick);
+ /** StatsPublisher process_memory_snapshot */
+ view.findViewById(R.id.send_on_process_memory_snapshot_config)
+ .setOnClickListener(this::onSendProcessMemorySnapshotConfigBtnClick);
+ view.findViewById(R.id.remove_on_process_memory_snapshot_config)
+ .setOnClickListener(this::onRemoveProcessMemorySnapshotConfigBtnClick);
+ view.findViewById(R.id.get_on_process_memory_snapshot_report)
+ .setOnClickListener(this::onGetProcessMemorySnapshotReportBtnClick);
/** Print mem info button */
view.findViewById(R.id.print_mem_info_btn).setOnClickListener(this::onPrintMemInfoBtnClick);
return view;
@@ -978,6 +1016,24 @@
mCarTelemetryManager.getFinishedReport(MEMORY_CONFIG_NAME, mExecutor, mListener);
}
+ private void onSendProcessMemorySnapshotConfigBtnClick(View view) {
+ mCarTelemetryManager.addMetricsConfig(
+ PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME,
+ METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.toByteArray(),
+ mExecutor,
+ mAddMetricsConfigCallback);
+ }
+
+ private void onRemoveProcessMemorySnapshotConfigBtnClick(View view) {
+ showOutput("Removing MetricsConfig that listens for PROCESS_MEMORY_SNAPSHOT...");
+ mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME);
+ }
+
+ private void onGetProcessMemorySnapshotReportBtnClick(View view) {
+ mCarTelemetryManager.getFinishedReport(
+ PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME, mExecutor, mListener);
+ }
+
/** Gets a MemoryInfo object for the device's current memory status. */
private ActivityManager.MemoryInfo getAvailableMemory() {
ActivityManager activityManager = getActivity().getSystemService(ActivityManager.class);
diff --git a/tests/OemCarServiceTestApp/Android.bp b/tests/OemCarServiceTestApp/Android.bp
new file mode 100644
index 0000000..002f401
--- /dev/null
+++ b/tests/OemCarServiceTestApp/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "OemCarServiceTestApp",
+ srcs: ["src/**/*.java"],
+ min_sdk_version: "33",
+ privileged: true,
+ certificate: "platform",
+ platform_apis: true,
+ libs: ["android.car-system-stubs"],
+}
diff --git a/tests/OemCarServiceTestApp/AndroidManifest.xml b/tests/OemCarServiceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..9851015
--- /dev/null
+++ b/tests/OemCarServiceTestApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.oemcarservice.testapp">
+
+ <application>
+ <service android:name="com.android.car.oemcarservice.testapp.OemCarServiceImpl"
+ android:directBootAware="true"
+ android:permission="android.car.permission.BIND_OEM_CAR_SERVICE"
+ android:exported="true">
+ </service>
+ </application>
+</manifest>
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
new file mode 100644
index 0000000..b6ab216
--- /dev/null
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarAudioFocusServiceImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.oemcarservice.testapp;
+
+import android.car.oem.OemCarAudioFocusService;
+import android.media.AudioFocusInfo;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+public final class OemCarAudioFocusServiceImpl implements OemCarAudioFocusService {
+
+ private static final String TAG = OemCarAudioFocusServiceImpl.class.getSimpleName();
+
+ public OemCarAudioFocusServiceImpl() {
+ Log.d(TAG, "constructor");
+ }
+
+ @Override
+ public void init() {
+ Log.d(TAG, "init");
+
+ }
+
+ @Override
+ public void release() {
+ Log.d(TAG, "release");
+ }
+
+ @Override
+ public void onCarServiceReady() {
+ Log.d(TAG, "onCarServiceReady");
+ // Do any CarService calls
+ }
+
+ @Override
+ public void dump(PrintWriter writer, String[] args) {
+ Log.d(TAG, "dump");
+ writer.println("Dump OemCarAudioFocusServiceImpl");
+ }
+
+ @Override
+ public void audioFocusChanged(List<AudioFocusInfo> currentFocusHolders,
+ List<AudioFocusInfo> currentFocusLosers, int zoneId) {
+ Log.d(TAG, "OemCarAudioFocusServiceImpl audioFocusChanged called");
+ }
+
+}
diff --git a/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
new file mode 100644
index 0000000..4aec93c
--- /dev/null
+++ b/tests/OemCarServiceTestApp/src/com/android/car/oemcarservice/testapp/OemCarServiceImpl.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 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.oemcarservice.testapp;
+
+import android.car.CarVersion;
+import android.car.oem.OemCarAudioFocusService;
+import android.car.oem.OemCarService;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public final class OemCarServiceImpl extends OemCarService {
+
+ private static final String TAG = OemCarServiceImpl.class.getSimpleName();
+ private static final CarVersion SUPPORTED_CAR_VERSION =
+ CarVersion.VERSION_CODES.TIRAMISU_2;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private OemCarAudioFocusServiceImpl mOemCarAudioFocusServiceImpl;
+
+ @Override
+ public void onCreate() {
+ Log.d(TAG, "onCreate");
+
+ // Initialize all subcomponents.
+ synchronized (mLock) {
+ mOemCarAudioFocusServiceImpl = new OemCarAudioFocusServiceImpl();
+ }
+ super.onCreate();
+ }
+
+
+ @Override
+ public void onDestroy() {
+ Log.d(TAG, "onDestroy");
+ // Releases resource from subcomponents.
+ synchronized (mLock) {
+ mOemCarAudioFocusServiceImpl = null;
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ Log.d(TAG, "dump");
+ writer.println("Dump OemCarServiceImpl");
+ writer.println("SUPPORTED_CAR_VERSION:" + SUPPORTED_CAR_VERSION);
+
+ }
+
+ @Override
+ public OemCarAudioFocusService getOemAudioFocusService() {
+ synchronized (mLock) {
+ Log.d(TAG, "getOemAudioFocusService returned " + mOemCarAudioFocusServiceImpl);
+ return mOemCarAudioFocusServiceImpl;
+ }
+ }
+
+ @Override
+ public void onCarServiceReady() {
+ Log.d(TAG, "onCarServiceReady");
+ }
+
+ @Override
+ public CarVersion getSupportedCarVersion() {
+ Log.d(TAG, "OemCarServiceImpl getSupportedCarVersion called");
+ return SUPPORTED_CAR_VERSION;
+ }
+
+}
diff --git a/tests/carservice_unit_test/res/raw/car_api_classes.txt b/tests/carservice_unit_test/res/raw/car_api_classes.txt
index 11fc354..bbcfc78 100644
--- a/tests/carservice_unit_test/res/raw/car_api_classes.txt
+++ b/tests/carservice_unit_test/res/raw/car_api_classes.txt
@@ -172,6 +172,9 @@
android.car.occupantawareness.OccupantAwarenessManager$ChangeCallback
android.car.occupantawareness.Point3D
android.car.occupantawareness.SystemStatusEvent
+android.car.oem.OemCarAudioFocusService
+android.car.oem.OemCarService
+android.car.oem.OemCarServiceComponent
android.car.os.CarPerformanceManager
android.car.os.CarPerformanceManager$SetSchedulerFailedException
android.car.os.CarPerformanceManager$CpuAvailabilityChangeListener
diff --git a/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..b9dd072
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- 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.
+-->
+
+<powerPolicy version="1.0">
+
+ <policyGroups defaultPolicyGroup="someGroup">
+ <policyGroup id="mixed_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+ </policyGroup>
+ </policyGroups>
+
+ <policies>
+ <policy id="expected_to_be_registered">
+ <otherComponents behavior="on"/>
+ </policy>
+ </policies>
+
+ <systemPolicyOverrides>
+ <policy id="system_power_policy_incorrect_id">
+ <component id="POWER_COMPONENT_NFC">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..76cc501
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- 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.
+-->
+
+<powerPolicy version="1.0">
+
+ <policyGroups defaultPolicyGroup="mixed_policy_group">
+ <policyGroup id="basic_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+ <defaultPolicy state="On" id="policy_id_other_untouched"/>
+ </policyGroup>
+ <policyGroup id="no_default_policy_group">
+ <noDefaultPolicy state="WaitForVHAL"/>
+ <noDefaultPolicy state="On"/>
+ </policyGroup>
+ <policyGroup id="mixed_policy_group">
+ <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+ <noDefaultPolicy state="On"/>
+ </policyGroup>
+ </policyGroups>
+
+ <policies>
+ <policy id="expected_to_be_registered">
+ <otherComponents behavior="on"/>
+ </policy>
+ <policy id="policy_id_other_off">
+ <otherComponents behavior="off"/>
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_DISPLAY">off</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ <policy id="policy_id_other_untouched">
+ <otherComponents behavior="untouched"/>
+ <component id="POWER_COMPONENT_AUDIO">on</component>
+ <component id="POWER_COMPONENT_DISPLAY">on</component>
+ <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+ </policy>
+ <policy id="policy_id_other_on">
+ <otherComponents behavior="on"/>
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ <policy id="policy_id_other_none">
+ <component id="POWER_COMPONENT_AUDIO">off</component>
+ <component id="POWER_COMPONENT_WIFI">on</component>
+ <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </policies>
+
+ <systemPolicyOverrides>
+ <policy id="system_power_policy_no_user_interaction">
+ <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+ <component id="POWER_COMPONENT_NFC">on</component>
+ <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+ </policy>
+ </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
new file mode 100644
index 0000000..2c60199
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/OemCarServiceTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 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 android.car.oem;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.CarVersion;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.content.pm.PackageManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class OemCarServiceTest extends AbstractExtendedMockitoTestCase {
+
+ private final CarVersion mCarVersionForTesting = CarVersion.VERSION_CODES.TIRAMISU_2;
+
+ private TestOemCarService mTestOemCarService = new TestOemCarService();
+ private IOemCarService mOemCarService = IOemCarService.Stub
+ .asInterface(mTestOemCarService.onBind(null));
+
+ @Mock
+ private IOemCarServiceCallback mIOemCarServiceCallback;
+
+ @Mock
+ private OemCarAudioFocusService mOemCarAudioFocusService;
+
+ @Test
+ public void testPermissionCheckForAll() throws Exception {
+ // Without correct permission, SecurityException will be thrown.
+ assertThrows(SecurityException.class,
+ () -> mOemCarService.getSupportedCarVersion());
+ assertThrows(SecurityException.class,
+ () -> mOemCarService.getOemAudioFocusService());
+ assertThrows(SecurityException.class,
+ () -> mOemCarService.onCarServiceReady(mIOemCarServiceCallback));
+ }
+
+ @Test
+ public void testGetSupportedCarVersion() throws Exception {
+ mockCallerPemission();
+
+ assertThat(mOemCarService.getSupportedCarVersion()).isEqualTo(mCarVersionForTesting);
+ }
+
+ @Test
+ public void testGetOemAudioFocusService_notNull() throws Exception {
+ TestOemCarService testOemCarService = new TestOemCarService();
+ testOemCarService.mockCheckCallingPermission();
+ testOemCarService.mockOemAudioFocusService();
+ testOemCarService.onCreate();
+ IOemCarService oemCarService = IOemCarService.Stub
+ .asInterface(testOemCarService.onBind(null));
+
+ assertThat(oemCarService.getOemAudioFocusService()).isNotNull();
+ }
+
+ @Test
+ public void testGetOemAudioFocusService_null() throws Exception {
+ mockCallerPemission();
+
+ assertThat(mOemCarService.getOemAudioFocusService()).isNull();
+ }
+
+ private void mockCallerPemission() {
+ mTestOemCarService.mockCheckCallingPermission();
+ }
+
+ private final class TestOemCarService extends OemCarService {
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mMockAudioFocusService;
+ @GuardedBy("mLock")
+ private boolean mAllowCallingPermission;
+
+ @Override
+ public CarVersion getSupportedCarVersion() {
+ return mCarVersionForTesting;
+ }
+
+ @Override
+ public OemCarAudioFocusService getOemAudioFocusService() {
+ synchronized (mLock) {
+ if (mMockAudioFocusService) {
+ return mOemCarAudioFocusService;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int checkCallingPermission(String permission) {
+ synchronized (mLock) {
+ return mAllowCallingPermission ? PackageManager.PERMISSION_GRANTED
+ : PackageManager.PERMISSION_DENIED;
+ }
+ }
+
+ void mockCheckCallingPermission() {
+ synchronized (mLock) {
+ mAllowCallingPermission = true;
+ }
+ }
+
+ void mockOemAudioFocusService() {
+ synchronized (mLock) {
+ mMockAudioFocusService = true;
+ }
+ }
+
+ @Override
+ public void onCarServiceReady() {
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
index 621c9fc..3c80203 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/NotificationHelperTest.java
@@ -22,7 +22,6 @@
import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION;
import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS;
-import static com.android.car.admin.NotificationHelper.CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP;
import static com.android.car.admin.NotificationHelper.CHANNEL_ID_DEFAULT;
import static com.android.car.admin.NotificationHelper.INTENT_EXTRA_NOTIFICATION_ID;
import static com.android.car.admin.NotificationHelper.NEW_USER_DISCLAIMER_NOTIFICATION_ID;
@@ -188,23 +187,19 @@
SparseArray<Notification> expectedNotificationsById = new SparseArray<>();
expectedNotificationsById.put(169, constructNotification(userHandle, "system_package.A",
- /* notificationId= */ 169, NotificationManager.IMPORTANCE_HIGH,
- /* isBundledApp= */ true));
+ /* notificationId= */ 169, NotificationManager.IMPORTANCE_HIGH));
expectedNotificationsById.put(150, constructNotification(userHandle, "vendor_package.A",
- /* notificationId= */ 150, NotificationManager.IMPORTANCE_HIGH,
- /* isBundledApp= */ true));
+ /* notificationId= */ 150, NotificationManager.IMPORTANCE_HIGH));
expectedNotificationsById.put(151, constructNotification(userHandle,
"third_party_package.A", /* notificationId= */ 151,
- NotificationManager.IMPORTANCE_HIGH, /* isBundledApp= */ false));
+ NotificationManager.IMPORTANCE_HIGH));
expectedNotificationsById.put(152, constructNotification(userHandle, "system_package.B",
- /* notificationId= */ 152, NotificationManager.IMPORTANCE_DEFAULT,
- /* isBundledApp= */ true));
+ /* notificationId= */ 152, NotificationManager.IMPORTANCE_DEFAULT));
expectedNotificationsById.put(153, constructNotification(userHandle, "vendor_package.B",
- /* notificationId= */ 153, NotificationManager.IMPORTANCE_DEFAULT,
- /* isBundledApp= */ true));
+ /* notificationId= */ 153, NotificationManager.IMPORTANCE_DEFAULT));
expectedNotificationsById.put(154, constructNotification(userHandle,
"third_party_package.B", /* notificationId= */ 154,
- NotificationManager.IMPORTANCE_DEFAULT, /* isBundledApp= */ false));
+ NotificationManager.IMPORTANCE_DEFAULT));
captureAndVerifyUserNotifications(expectedNotificationsById, userHandle);
}
@@ -246,50 +241,36 @@
}
private Notification constructNotification(UserHandle userHandle, String packageName,
- int notificationId, int importance, boolean isBundledApp) {
+ int notificationId, int importance) {
CharSequence title = TextUtils.expandTemplate(
mSpiedContext.getText(R.string.resource_overuse_notification_title),
packageName + APP_SUFFIX);
String actionTitlePrioritizeApp = mSpiedContext.getString(
R.string.resource_overuse_notification_button_prioritize_app);
+ String contextText =
+ mSpiedContext.getString(R.string.resource_overuse_notification_text_disabled_app);
+ String negativeActionText = mSpiedContext.getString(
+ R.string.resource_overuse_notification_button_close_app);
+
PendingIntent positiveActionPendingIntent =
NotificationHelper.getPendingIntent(mSpiedContext,
CAR_WATCHDOG_ACTION_LAUNCH_APP_SETTINGS, userHandle, packageName,
notificationId);
- PendingIntent deletePendingIntent = NotificationHelper.getPendingIntent(mSpiedContext,
+ PendingIntent negativeActionPendingIntent = NotificationHelper.getPendingIntent(
+ mSpiedContext,
CAR_WATCHDOG_ACTION_DISMISS_RESOURCE_OVERUSE_NOTIFICATION, userHandle, packageName,
notificationId);
- String text;
- String negativeActionText;
- PendingIntent negativeActionPendingIntent;
- if (isBundledApp) {
- text = mSpiedContext.getString(R.string.resource_overuse_notification_text_disable_app);
- negativeActionText = mSpiedContext.getString(
- R.string.resource_overuse_notification_button_disable_app);
- negativeActionPendingIntent = NotificationHelper.getPendingIntent(mSpiedContext,
- CAR_WATCHDOG_ACTION_RESOURCE_OVERUSE_DISABLE_APP, userHandle,
- packageName, notificationId);
- } else {
- text = mSpiedContext.getString(
- R.string.resource_overuse_notification_text_uninstall_app);
- negativeActionText = mSpiedContext.getString(
- R.string.resource_overuse_notification_button_uninstall_app);
- negativeActionPendingIntent = positiveActionPendingIntent;
- }
- text += " " + mSpiedContext.getString(
- R.string.resource_overuse_notification_text_prioritize_app);
-
return NotificationHelper.newNotificationBuilder(mSpiedContext, importance)
.setSmallIcon(R.drawable.car_ic_warning)
.setContentTitle(title)
- .setContentText(text)
+ .setContentText(contextText)
.setCategory(Notification.CATEGORY_CAR_WARNING)
.addAction(new Notification.Action.Builder(/* icon= */ null,
- actionTitlePrioritizeApp, positiveActionPendingIntent).build())
- .addAction(new Notification.Action.Builder(/* icon= */ null,
negativeActionText, negativeActionPendingIntent).build())
- .setDeleteIntent(deletePendingIntent)
+ .addAction(new Notification.Action.Builder(/* icon= */ null,
+ actionTitlePrioritizeApp, positiveActionPendingIntent).build())
+ .setDeleteIntent(negativeActionPendingIntent)
.build();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
index c6f56cf..0b522d7 100644
--- a/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hardware/power/CarPowerManagerUnitTest.java
@@ -74,6 +74,7 @@
import com.android.car.systeminterface.SystemStateInterface;
import com.android.car.test.utils.TemporaryFile;
import com.android.car.user.CarUserService;
+import com.android.compatibility.common.util.PollingCheck;
import com.android.internal.annotations.GuardedBy;
import org.junit.After;
@@ -315,6 +316,11 @@
@Test
public void testAddPowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
+
+ // Prepare for test
+ applyInitialPolicyForTest(/* policyName= */ "audio_off", /* enabledComponents= */
+ new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"});
+
String policyId = "audio_on_wifi_off";
mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
@@ -332,8 +338,10 @@
mCarPowerManager.addPowerPolicyListener(mExecutor, filterLocation, listenerLocation);
mCarPowerManager.applyPowerPolicy(policyId);
- assertThat(listenerAudio.getCurrentPolicyId()).isEqualTo(policyId);
- assertThat(listenerWifi.getCurrentPolicyId()).isEqualTo(policyId);
+ assertPowerPolicyId(listenerAudio, policyId, "Current policy ID of listenerAudio is not "
+ + policyId);
+ assertPowerPolicyId(listenerWifi, policyId, "Current policy ID of listenerWifi is not "
+ + policyId);
assertThat(listenerLocation.getCurrentPolicyId()).isNull();
}
@@ -372,6 +380,11 @@
@Test
public void testRemovePowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
+
+ String initialPolicyId = "audio_off";
+ applyInitialPolicyForTest(initialPolicyId, /* enabledComponents= */
+ new String[]{}, /* disabledComponents= */ new String[]{"AUDIO"});
+
String policyId = "audio_on_wifi_off";
mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
MockedPowerPolicyListener listenerOne = new MockedPowerPolicyListener();
@@ -384,8 +397,18 @@
mCarPowerManager.removePowerPolicyListener(listenerOne);
mCarPowerManager.applyPowerPolicy(policyId);
- assertThat(listenerOne.getCurrentPolicyId()).isNull();
- assertThat(listenerTwo.getCurrentPolicyId()).isEqualTo(policyId);
+ String receivedPolicyId = listenerOne.getCurrentPolicyId();
+ assertWithMessage("Policy ID received after removing listeners")
+ .that(receivedPolicyId == null || receivedPolicyId.equals(initialPolicyId))
+ .isTrue();
+ assertPowerPolicyId(listenerTwo, policyId, "Current policy ID of listenerTwo is not "
+ + policyId);
+ }
+
+ private void applyInitialPolicyForTest(String policyName, String[] enabledComponents,
+ String[] disabledComponents) {
+ mService.definePowerPolicy(policyName, enabledComponents, disabledComponents);
+ mCarPowerManager.applyPowerPolicy(policyName);
}
@Test
@@ -486,6 +509,12 @@
referenceStates).inOrder();
}
+ private static void assertPowerPolicyId(MockedPowerPolicyListener listener, String policyId,
+ String errorMsg) throws Exception {
+ PollingCheck.check(errorMsg, WAIT_TIMEOUT_MS,
+ () -> policyId.equals(listener.getCurrentPolicyId()));
+ }
+
private static boolean isCompletionAllowed(@CarPowerManager.CarPowerState int state) {
switch (state) {
case CarPowerManager.STATE_PRE_SHUTDOWN_PREPARE:
diff --git a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
index 3661834..fdcec3b 100644
--- a/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/media/CarMediaServiceTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -290,6 +291,21 @@
assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
.isEqualTo(MEDIA_COMPONENT2);
+ verify(mContext, times(2)).startForegroundService(any());
+ }
+
+ @Test
+ public void testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource() {
+ mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
+
+ // setup media source info only for MEDIA Component
+ // second one will stay null
+ initMediaService(MEDIA_CLASS);
+
+ // New Media source should be null
+ assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull();
+ // service start should happen on init but not on media source change
+ verify(mContext, times(1)).startForegroundService(any());
}
@Test
@@ -303,6 +319,7 @@
.isEqualTo(MEDIA_COMPONENT2);
assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
.isEqualTo(MEDIA_COMPONENT);
+ verify(mContext, times(2)).startForegroundService(any());
}
@Test
@@ -316,6 +333,7 @@
.isEqualTo(MEDIA_COMPONENT2);
assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
.isEqualTo(MEDIA_COMPONENT2);
+ verify(mContext, times(2)).startForegroundService(any());
}
@Test
@@ -326,6 +344,7 @@
assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
.isEqualTo(MEDIA_COMPONENT);
+ verify(mContext, times(1)).startForegroundService(any());
}
private void initMediaService(String... classesToResolve) {
diff --git a/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java
new file mode 100644
index 0000000..e71c4cd
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceHelperTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Process;
+import android.os.RemoteException;
+
+import com.android.car.R;
+import com.android.car.oem.CarOemProxyServiceHelper.CallbackForDelayedResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+
+public final class CarOemProxyServiceHelperTest extends AbstractExtendedMockitoTestCase {
+ private static final String CALLER_TAG = "test";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private Resources mResources;
+
+ private CarOemProxyServiceHelper mCarOemProxyServiceHelper;
+
+ @Before
+ public void setUp() throws Exception {
+ when(mContext.getResources()).thenReturn(mResources);
+ mockCallTimeout(/* timeoutMs= */ 5000);
+ mCarOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+ }
+
+ @Override
+ protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+ session.spyStatic(Process.class);
+ }
+
+ @Test
+ public void testDoBinderTimedCallWithDefault_returnCalculatedValue() throws Exception {
+ assertThat(mCarOemProxyServiceHelper.doBinderTimedCallWithDefaultValue(CALLER_TAG,
+ () -> "value", /* defaultValue= */ "default")).isEqualTo("value");
+ }
+
+ @Test
+ public void testDoBinderTimedCallWithDefault_returnDefaultValue() throws Exception {
+ mockCallTimeout(/* timeoutMs= */ 10);
+ CarOemProxyServiceHelper carOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+
+ assertThat(carOemProxyServiceHelper.doBinderTimedCallWithDefaultValue(CALLER_TAG, () -> {
+ Thread.sleep(1000); // test will not wait for this timeout
+ return "value";
+ }, /* defaultValue= */ "default")).isEqualTo("default");
+
+ }
+
+ @Test
+ public void testDoBinderTimedCall_timeoutException() throws Exception {
+ assertThrows(TimeoutException.class, () -> {
+ mCarOemProxyServiceHelper.doBinderTimedCallWithTimeout(CALLER_TAG, () -> {
+ Thread.sleep(1000); // test will not wait for this timeout
+ return 42;
+ }, /* timeout= */ 10);
+ });
+ }
+
+ @Test
+ public void testDoBinderTimedCall_returnCalculatedValue() throws Exception {
+ assertThat(mCarOemProxyServiceHelper.doBinderTimedCallWithTimeout(CALLER_TAG, () -> 42,
+ /* timeout= */ 1000)).isEqualTo(42);
+ }
+
+ @Test
+ public void testDoBinderCallTimeoutCrash_returnCalculatedValue() throws Exception {
+ assertThat(
+ mCarOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> 42).get())
+ .isEqualTo(42);
+ }
+
+ @Test
+ public void testDoBinderCallTimeoutCrash_withCrash() throws Exception {
+ doAnswer(inv -> {
+ throw new IllegalStateException();
+ }).when(() -> Process.killProcess(anyInt()));
+
+ mockCallTimeout(/* timeoutMs= */ 10);
+ CarOemProxyServiceHelper carOemProxyServiceHelper = new CarOemProxyServiceHelper(mContext);
+
+ assertThrows(IllegalStateException.class, () -> {
+ carOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> {
+ Thread.sleep(1000); // test will not wait for this timeout
+ return 42;
+ });
+ });
+ }
+
+ @Test
+ public void testDoBinderCallTimeoutCrash_withExecutionException() throws Exception {
+ assertThat(mCarOemProxyServiceHelper.doBinderCallWithTimeoutCrash(CALLER_TAG, () -> {
+ if (true) {
+ throw new RemoteException();
+ }
+ return 42;
+ }).isEmpty()).isTrue();
+ }
+
+ @Test
+ public void testDoBinderCallWithDefaultValueAndDelayedWaitAndCrash() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ int delayFromOemCallMs = 100;
+ CallbackForDelayedResult<String> callback = (result) -> latch.countDown();
+
+ Optional<String> result = mCarOemProxyServiceHelper
+ .doBinderCallWithDefaultValueAndDelayedWaitAndCrash(
+ CALLER_TAG,
+ () -> {
+ Thread.sleep(delayFromOemCallMs);
+ return "result";
+ },
+ /* defaultTimeoutMs= */ 10,
+ callback);
+ assertThat(result.isEmpty()).isTrue();
+ JavaMockitoHelper.await(latch, 1000); //latch would be waiting at max delayFromOemCallMs
+ assertThat(latch.getCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testCrashCarService() {
+ doAnswer(inv -> {
+ throw new IllegalStateException();
+ }).when(() -> Process.killProcess(anyInt()));
+
+ assertThrows(IllegalStateException.class,
+ () -> mCarOemProxyServiceHelper.crashCarService(""));
+ }
+
+ private void mockCallTimeout(int timeoutMs) {
+ when(mResources.getInteger(R.integer.config_oemCarService_regularCall_timeout_ms))
+ .thenReturn(timeoutMs);
+ when(mResources.getInteger(R.integer.config_oemCarService_crashCall_timeout_ms))
+ .thenReturn(timeoutMs);
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java
new file mode 100644
index 0000000..5a352a6
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/oem/CarOemProxyServiceTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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.oem;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.CarVersion;
+import android.car.builtin.content.pm.PackageManagerHelper;
+import android.car.oem.IOemCarAudioFocusService;
+import android.car.oem.IOemCarService;
+import android.car.oem.IOemCarServiceCallback;
+import android.car.test.mocks.AbstractExtendedMockitoTestCase;
+import android.car.test.mocks.JavaMockitoHelper;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+
+import com.android.car.R;
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+
+public final class CarOemProxyServiceTest extends AbstractExtendedMockitoTestCase {
+
+ private static final String COMPONENT_NAME = "android.car.test/unittest";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private CarOemProxyServiceHelper mCarOemProxyServiceHelper;
+ @Captor
+ ArgumentCaptor<String> mReasonCapture;
+ @Captor
+ ArgumentCaptor<ServiceConnection> mConnectionCapture;
+
+ private final TestOemCarService mTestOemCarService = new TestOemCarService();
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ @Override
+ protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
+ session.spyStatic(PackageManagerHelper.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mockCallTimeout(/* timeoutMs= */ 5000);
+ }
+
+ @Test
+ public void testFeatureDisabled() throws Exception {
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+
+ assertThat(carOemProxyService.isOemServiceEnabled()).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabled() throws Exception {
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+
+ assertThat(carOemProxyService.isOemServiceEnabled()).isTrue();
+ assertThat(carOemProxyService.getOemServiceName()).isEqualTo(COMPONENT_NAME);
+ }
+
+ @Test
+ public void testOemServiceCalledPriorToInit() throws Exception {
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+ mockServiceConnection();
+
+ assertThrows(IllegalStateException.class,
+ () -> carOemProxyService.getCarOemAudioFocusService());
+ }
+
+ @Test
+ public void testCarServiceCrash_oemNotConnected() throws Exception {
+ mockCallTimeout(/* timeoutMs= */ 100);
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext,
+ mCarOemProxyServiceHelper, mHandler);
+
+ //call will wait for OEM service connected
+ carOemProxyService.onInitComplete();
+ waitForHandlerThreadToFinish();
+
+ // First it will call crash with "OEM Service not connected", as it is mocked, it would
+ // continue with other calls.
+ verify(mCarOemProxyServiceHelper, times(2)).crashCarService(mReasonCapture.capture());
+ assertThat(mReasonCapture.getAllValues()).containsExactly("OEM Service not connected",
+ "OEM Service not ready");
+ }
+
+ @Test
+ public void testCarServiceCrash_oemNotReady() throws Exception {
+ mockCallTimeout(/* timeoutMs= */ 100);
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext,
+ mCarOemProxyServiceHelper, mHandler);
+ mockServiceConnection();
+
+ //call will wait for OEM service ready
+ carOemProxyService.onInitComplete();
+ waitForHandlerThreadToFinish();
+
+ verify(mCarOemProxyServiceHelper).crashCarService("OEM Service not ready");
+ }
+
+ @Test
+ public void testOemServiceIsReady() throws Exception {
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+ mockServiceConnection();
+ mockServiceReady();
+ carOemProxyService.onInitComplete();
+
+ eventually(() -> assertWithMessage("Oem Service not ready.")
+ .that(carOemProxyService.isOemServiceReady()).isTrue());
+
+ assertThat(carOemProxyService.getCarOemAudioFocusService()).isNull();
+ }
+
+ @Test
+ public void testCallbackWhenOemServiceIsReady() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ mockOemCarServiceComponent();
+ CarOemProxyService carOemProxyService = new CarOemProxyService(mContext);
+ mockServiceConnection();
+ mockServiceReady();
+
+ carOemProxyService.registerCallback(() -> latch.countDown());
+ carOemProxyService.onInitComplete();
+
+ JavaMockitoHelper.await(latch, 5000);
+ }
+
+ private void waitForHandlerThreadToFinish() {
+ int timeoutMs = 2000;
+ assertWithMessage("handler not idle in %sms", timeoutMs)
+ .that(mHandler.runWithScissors(() -> {}, timeoutMs)).isTrue();
+ }
+
+ private void mockServiceConnection() {
+ verify(mContext).bindServiceAsUser(any(), mConnectionCapture.capture(), anyInt(), any());
+ ServiceConnection connection = mConnectionCapture.getValue();
+ connection.onServiceConnected(ComponentName.unflattenFromString(COMPONENT_NAME),
+ mTestOemCarService);
+ }
+
+ private void mockOemCarServiceComponent() throws Exception {
+ when(mResources.getString(R.string.config_oemCarService)).thenReturn(COMPONENT_NAME);
+ // make it a valid component.
+ String packageName = ComponentName.unflattenFromString(COMPONENT_NAME).getPackageName();
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ when(mPackageManager.getPackageInfo(packageName, 0)).thenReturn(packageInfo);
+ doReturn(true).when(() -> PackageManagerHelper.isSystemApp(any()));
+ when(mContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true);
+ }
+
+ private void mockCallTimeout(int timeoutMs) {
+ when(mResources.getInteger(R.integer.config_oemCarService_connection_timeout_ms))
+ .thenReturn(timeoutMs);
+ when(mResources.getInteger(R.integer.config_oemCarService_serviceReady_timeout_ms))
+ .thenReturn(timeoutMs);
+ }
+
+ private void mockServiceReady() throws Exception {
+ mTestOemCarService.mockServiceReady();
+ }
+
+ private final class TestOemCarService extends IOemCarService.Stub {
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mMockedServiceReady;
+
+ public void mockServiceReady() {
+ synchronized (mLock) {
+ mMockedServiceReady = true;
+ }
+ }
+
+ @Override
+ public IOemCarAudioFocusService getOemAudioFocusService() {
+ return null;
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ }
+
+ @Override
+ public CarVersion getSupportedCarVersion() {
+ return CarVersion.VERSION_CODES.TIRAMISU_2;
+ }
+
+ @Override
+ public void onCarServiceReady(IOemCarServiceCallback callback) throws RemoteException {
+ boolean mockedServiceReady;
+ synchronized (mLock) {
+ mockedServiceReady = mMockedServiceReady;
+ }
+ if (mockedServiceReady) {
+ callback.sendOemCarServiceReady();
+ }
+ }
+
+ @Override
+ public String getAllStackTraces() {
+ return "";
+ }
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
index 8ee9bc0..67a55ed 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/CarPowerManagementServiceUnitTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.car.Car;
import android.car.ICarResultReceiver;
@@ -90,7 +91,6 @@
import java.io.StringWriter;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -109,6 +109,7 @@
public static final String SYSTEM_POWER_POLICY_ALL_ON = "system_power_policy_all_on";
public static final String SYSTEM_POWER_POLICY_NO_USER_INTERACTION =
"system_power_policy_no_user_interaction";
+ public static final String SYSTEM_POWER_POLICY_INITIAL_ON = "system_power_policy_initial_on";
private final MockDisplayInterface mDisplayInterface = new MockDisplayInterface();
private final MockSystemStateInterface mSystemStateInterface = new MockSystemStateInterface();
@@ -187,6 +188,8 @@
doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
when(mResources.getInteger(R.integer.maxGarageModeRunningDurationInSecs))
.thenReturn(900);
+ when(mResources.getInteger(R.integer.config_maxSuspendWaitDuration))
+ .thenReturn(WAKE_UP_DELAY);
doReturn(true).when(() -> VoiceInteractionHelper.isAvailable());
doAnswer(invocation -> {
mVoiceInteractionEnabled = (boolean) invocation.getArguments()[0];
@@ -214,20 +217,12 @@
assertStateReceived(MockedPowerHalService.SET_WAIT_FOR_VHAL, 0);
}
- @Test
- public void testDisplayOn() throws Exception {
- // start with display off
- mSystemInterface.setDisplayState(false);
- mDisplayInterface.waitForDisplayOff(WAIT_TIMEOUT_MS);
- // Transition to ON state
- mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
- // display should be turned on as it started with off state.
- mDisplayInterface.waitForDisplayOn(WAIT_TIMEOUT_MS);
- }
@Test
public void testShutdown() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -247,6 +242,9 @@
@Test
public void testCanHibernate() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_EXIT);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -267,6 +265,9 @@
@Test
public void testHibernateImmediately() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_HIBERNATION_EXIT);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -287,6 +288,8 @@
@Test
public void testShutdownImmediately() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -308,6 +311,7 @@
@Test
public void testSuspend() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -323,6 +327,8 @@
@Test
public void testShutdownOnSuspend() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -354,6 +360,7 @@
@Test
public void testShutdownCancel() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -376,6 +383,9 @@
@Test
public void testSleepImmediately() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
// Transition to ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -397,6 +407,7 @@
@Test
public void testShutdownWithProcessing() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE, 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_START);
mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_START, WAIT_TIMEOUT_MS);
@@ -407,6 +418,8 @@
@Test
public void testSleepEntryAndWakeup() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.CAN_SLEEP));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY);
@@ -420,6 +433,10 @@
@Test
public void testShutdownPostponeAfterSuspend() throws Exception {
+ grantPowerPolicyPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
// Start in the ON state
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
@@ -437,7 +454,9 @@
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
// Second processing after wakeup
- assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+ assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
+ assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+ .isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
mService.setStateForWakeUp();
@@ -469,6 +488,8 @@
@Test
public void testRegisterListenerWithCompletion() throws Exception {
grantAdjustShutdownProcessPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
SparseBooleanArray stateMapToCompletion = new SparseBooleanArray();
ICarPowerStateListener listenerRegistered = new ICarPowerStateListener.Stub() {
@Override
@@ -508,6 +529,8 @@
@Test
public void testUnregisterListenerWithCompletion() throws Exception {
grantAdjustShutdownProcessPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
ICarPowerStateListener listenerUnregistered = new ICarPowerStateListener.Stub() {
@Override
public void onStateChanged(int state, long expirationTimeMs) {
@@ -531,6 +554,8 @@
@Test
public void testShutdownPrepareWithCompletion_timeout() throws Exception {
grantAdjustShutdownProcessPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
// Shortens the timeout for listen completion
when(mResources.getInteger(R.integer.config_preShutdownPrepareTimeout))
.thenReturn(10);
@@ -588,8 +613,9 @@
@Test
public void testApplyPowerPolicy() throws Exception {
grantPowerPolicyPermission();
- String policyId = "policy_id_audio_on";
- mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[0]);
+
+ String policyId = "policy_id_audio_off";
+ mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO"});
MockedPowerPolicyListener listenerToWait = new MockedPowerPolicyListener();
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
@@ -597,11 +623,10 @@
mService.applyPowerPolicy(policyId);
- CarPowerPolicy policy = mService.getCurrentPowerPolicy();
- assertThat(policy).isNotNull();
- assertThat(policy.getPolicyId()).isEqualTo(policyId);
+ waitForPowerPolicy(policyId);
assertThat(mPowerComponentHandler.getAccumulatedPolicy().getPolicyId()).isEqualTo(policyId);
- assertThat(listenerToWait.getCurrentPowerPolicy()).isNotNull();
+ PollingCheck.check("Current power policy of listener is null", WAIT_TIMEOUT_LONG_MS,
+ () -> listenerToWait.getCurrentPowerPolicy() != null);
assertThat(mPowerPolicyDaemon.getLastNotifiedPolicyId()).isEqualTo(policyId);
}
@@ -678,11 +703,12 @@
@Test
public void testAddPowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
- String policyId = "policy_id_enable_audio_wifi";
- mService.definePowerPolicy(policyId, new String[]{"AUDIO", "WIFI"}, new String[]{});
+
+ String policyIdEnableAudioWifi = "policy_id_enable_audio_wifi";
MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
MockedPowerPolicyListener listenerWifi = new MockedPowerPolicyListener();
MockedPowerPolicyListener listenerLocation = new MockedPowerPolicyListener();
+
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
CarPowerPolicyFilter filterWifi = new CarPowerPolicyFilter.Builder()
@@ -692,28 +718,53 @@
mService.addPowerPolicyListener(filterAudio, listenerAudio);
mService.addPowerPolicyListener(filterWifi, listenerWifi);
- mService.applyPowerPolicy(policyId);
- assertThat(listenerAudio.getCurrentPowerPolicy()).isNotNull();
- assertThat(listenerAudio.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
- assertThat(listenerWifi.getCurrentPowerPolicy()).isNotNull();
- assertThat(listenerWifi.getCurrentPowerPolicy().getPolicyId()).isEqualTo(policyId);
+ String policyIdAllOff = "all_off";
+ mService.definePowerPolicy(policyIdAllOff, new String[]{},
+ new String[]{"AUDIO", "WIFI", "DISPLAY"});
+ mService.applyPowerPolicy(policyIdAllOff);
+ waitForPowerPolicy(policyIdAllOff);
+
+ assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
+ PowerComponent.AUDIO)).isFalse();
+ assertThat(
+ mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.WIFI)).isFalse();
+ assertThat(mService.getCurrentPowerPolicy().isComponentEnabled(
+ PowerComponent.DISPLAY)).isFalse();
+
+ mService.definePowerPolicy(policyIdEnableAudioWifi, new String[]{"AUDIO", "WIFI"},
+ new String[]{});
+ mService.applyPowerPolicy(policyIdEnableAudioWifi);
+
+ waitForPolicyId(listenerAudio, policyIdEnableAudioWifi,
+ "Current power policy of listenerAudio is not " + policyIdEnableAudioWifi);
+ assertThat(
+ mService.getCurrentPowerPolicy().isComponentEnabled(PowerComponent.AUDIO)).isTrue();
+
+ waitForPolicyId(listenerWifi, policyIdEnableAudioWifi,
+ "Current power policy of listenerWifi is not " + policyIdEnableAudioWifi);
assertThat(listenerLocation.getCurrentPowerPolicy()).isNull();
}
@Test
public void testRemovePowerPolicyListener() throws Exception {
grantPowerPolicyPermission();
- String policyId = "policy_id_enable_audio_disable_wifi";
- mService.definePowerPolicy(policyId, new String[]{"AUDIO"}, new String[]{"WIFI"});
+
+ String policyId = "policy_id_disable_audio";
+ mService.definePowerPolicy(policyId, new String[]{}, new String[]{"AUDIO", "WIFI"});
MockedPowerPolicyListener listenerAudio = new MockedPowerPolicyListener();
+ MockedPowerPolicyListener referenceListenerAudio = new MockedPowerPolicyListener();
+
CarPowerPolicyFilter filterAudio = new CarPowerPolicyFilter.Builder()
.setComponents(PowerComponent.AUDIO).build();
mService.addPowerPolicyListener(filterAudio, listenerAudio);
+ mService.addPowerPolicyListener(filterAudio, referenceListenerAudio);
mService.removePowerPolicyListener(listenerAudio);
mService.applyPowerPolicy(policyId);
+ waitForPolicyId(referenceListenerAudio, policyId,
+ "Current power policy of referenceListenerAudio is not " + policyId);
assertThat(listenerAudio.getCurrentPowerPolicy()).isNull();
}
@@ -744,6 +795,10 @@
@Test
public void testPowerPolicyAfterShutdownCancel() throws Exception {
grantPowerPolicyPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_START);
+ assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+ .isEqualTo(SYSTEM_POWER_POLICY_INITIAL_ON);
mPowerHal.setCurrentPowerState(
new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
VehicleApPowerStateShutdownParam.SHUTDOWN_ONLY));
@@ -754,22 +809,44 @@
new PowerState(VehicleApPowerStateReq.CANCEL_SHUTDOWN, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_SHUTDOWN_CANCELLED);
- mPowerSignalListener.waitFor(PowerHalService.SET_WAIT_FOR_VHAL, WAIT_TIMEOUT_MS);
+ waitForPowerPolicy(SYSTEM_POWER_POLICY_INITIAL_ON);
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
- assertThat(mService.getCurrentPowerPolicy().getPolicyId())
- .isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
+ waitForPowerPolicy(SYSTEM_POWER_POLICY_ALL_ON);
+ }
+
+ @Test
+ public void testSuspendFailure() throws Exception {
+ suspendWithFailure(/* nextPowerState= */ null);
+ mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+ }
+
+ @Test
+ public void testSuspendFailureWithForbiddenTransition() throws Exception {
+ suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.ON);
+ mSystemStateInterface.waitForShutdown(WAIT_TIMEOUT_MS);
+ }
+
+ @Test
+ public void testSuspendFailureWithAllowedTransition() throws Exception {
+ mPowerSignalListener.addEventListener(PowerHalService.SET_SHUTDOWN_CANCELLED);
+ suspendWithFailure(/* nextPowerState= */ VehicleApPowerStateReq.CANCEL_SHUTDOWN);
+ mPowerSignalListener.waitFor(PowerHalService.SET_SHUTDOWN_CANCELLED, WAIT_TIMEOUT_MS);
}
@Test
public void testPowerPolicyOnSilentBoot() throws Exception {
grantPowerPolicyPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
mService.setSilentMode(SilentModeHandler.SILENT_MODE_FORCED_SILENT);
+ assertThat(mService.getCurrentPowerPolicy().getPolicyId())
+ .isEqualTo(SYSTEM_POWER_POLICY_NO_USER_INTERACTION);
+
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, /* param= */ 0));
assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_ON);
@@ -784,7 +861,35 @@
.isEqualTo(SYSTEM_POWER_POLICY_ALL_ON);
}
+ private void suspendWithFailure(Integer nextPowerState) throws Exception {
+ mSystemStateInterface.setSleepEntryResult(false);
+ mSystemStateInterface.setSimulateSleep(false);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_ON);
+
+ // Transition to ON state
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.ON, 0));
+ mPowerSignalListener.waitFor(PowerHalService.SET_ON, WAIT_TIMEOUT_MS);
+
+ mPowerHal.setCurrentPowerState(
+ new PowerState(
+ VehicleApPowerStateReq.SHUTDOWN_PREPARE,
+ VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY));
+ assertStateReceivedForShutdownOrSleepWithPostpone(PowerHalService.SET_DEEP_SLEEP_ENTRY, 0);
+ assertThat(mService.garageModeShouldExitImmediately()).isTrue();
+
+ mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.FINISHED, 0));
+
+ mSystemStateInterface.waitForDeepSleepEntry(WAIT_TIMEOUT_MS);
+
+ if (nextPowerState != null) {
+ mPowerHal.setCurrentPowerState(new PowerState(nextPowerState, 0));
+ }
+ }
+
private void suspendAndResume() throws Exception {
+ grantPowerPolicyPermission();
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_ENTRY);
+ mPowerSignalListener.addEventListener(PowerHalService.SET_DEEP_SLEEP_EXIT);
Log.d(TAG, "suspend()");
mVoiceInteractionEnabled = true;
mPowerHal.setCurrentPowerState(new PowerState(VehicleApPowerStateReq.SHUTDOWN_PREPARE,
@@ -803,8 +908,11 @@
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
mPowerSignalListener.waitFor(PowerHalService.SET_DEEP_SLEEP_EXIT, WAIT_TIMEOUT_MS);
mService.scheduleNextWakeupTime(WAKE_UP_DELAY);
+
// second processing after wakeup
- assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+ assertThat(mService.getCurrentPowerPolicy().getPolicyId()).isEqualTo(
+ SYSTEM_POWER_POLICY_INITIAL_ON);
+ assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
mFileHwStateMonitoring.write(NONSILENT_STRING); // Wake non-silently
mService.setStateForWakeUp();
@@ -830,7 +938,7 @@
mSystemStateInterface.waitForSleepEntryAndWakeup(WAIT_TIMEOUT_MS);
// Since we just woke up from shutdown, wake up time will be 0
assertStateReceived(PowerHalService.SET_DEEP_SLEEP_EXIT, 0);
- assertThat(mDisplayInterface.isDisplayEnabled()).isFalse();
+ assertThat(mDisplayInterface.isDisplayEnabled()).isTrue();
}
private void assertStateReceived(int expectedState, int expectedParam) throws Exception {
@@ -880,6 +988,23 @@
});
}
+ private void waitForPowerPolicy(String policyId) throws Exception {
+ PollingCheck.check("Policy id is not " + policyId, WAIT_TIMEOUT_LONG_MS,
+ () -> {
+ CarPowerPolicy policy = mService.getCurrentPowerPolicy();
+ return policy != null && policyId.equals(policy.getPolicyId());
+ });
+ }
+
+ private static void waitForPolicyId(MockedPowerPolicyListener listener, String policyId,
+ String errorMsg) throws Exception {
+ PollingCheck.check(errorMsg, WAIT_TIMEOUT_LONG_MS,
+ () -> {
+ CarPowerPolicy policy = listener.getCurrentPowerPolicy();
+ return policy != null && policyId.equals(policy.getPolicyId());
+ });
+ }
+
private static void waitForSemaphore(Semaphore semaphore, long timeoutMs)
throws InterruptedException {
if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
@@ -975,6 +1100,10 @@
private final Semaphore mShutdownWait = new Semaphore(0);
private final Semaphore mSleepWait = new Semaphore(0);
private final Semaphore mSleepExitWait = new Semaphore(0);
+
+ private boolean mSleepEntryResult = true;
+ private boolean mSimulateSleep = true;
+
private boolean mWakeupCausedByTimer = false;
@Override
@@ -988,7 +1117,12 @@
@Override
public boolean enterDeepSleep() {
- return simulateSleep();
+ if (mSimulateSleep) {
+ return simulateSleep();
+ }
+
+ mSleepWait.release();
+ return mSleepEntryResult;
}
@Override
@@ -999,10 +1133,10 @@
private boolean simulateSleep() {
mSleepWait.release();
try {
- mSleepExitWait.acquire();
+ mSleepExitWait.tryAcquire(WAIT_TIMEOUT_MS , TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
- return true;
+ return mSleepEntryResult;
}
public void waitForSleepEntryAndWakeup(long timeoutMs) throws Exception {
@@ -1032,6 +1166,18 @@
public boolean isSystemSupportingHibernation() {
return true;
}
+
+ public void setSleepEntryResult(boolean sleepEntryResult) {
+ mSleepEntryResult = sleepEntryResult;
+ }
+
+ public void setSimulateSleep(boolean simulateSleep) {
+ mSimulateSleep = simulateSleep;
+ }
+
+ public void waitForDeepSleepEntry(long waitTimeoutMs) throws InterruptedException {
+ waitForSemaphore(mSleepWait, waitTimeoutMs);
+ }
}
private static final class MockWakeLockInterface implements WakeLockInterface {
@@ -1078,16 +1224,16 @@
private PowerSignalListener() {
mSemaphores = new SparseArray<>();
- mSemaphores.put(PowerHalService.SET_ON, new Semaphore(0));
- mSemaphores.put(PowerHalService.SET_SHUTDOWN_START, new Semaphore(0));
- mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_ENTRY, new Semaphore(0));
- mSemaphores.put(PowerHalService.SET_DEEP_SLEEP_EXIT, new Semaphore(0));
+ }
+
+ public void addEventListener(int eventId) {
+ mSemaphores.put(eventId, new Semaphore(0));
}
public void waitFor(int signal, long timeoutMs) throws Exception {
Semaphore semaphore = mSemaphores.get(signal);
if (semaphore == null) {
- return;
+ throw new IllegalArgumentException("no semaphore registered for event = " + signal);
}
waitForSemaphore(semaphore, timeoutMs);
}
@@ -1103,7 +1249,7 @@
}
static final class FakeCarPowerPolicyDaemon extends ICarPowerPolicySystemNotification.Stub {
- private String mLastNofitiedPolicyId;
+ private String mLastNotifiedPolicyId;
private String mLastDefinedPolicyId;
@Override
@@ -1114,7 +1260,7 @@
@Override
public void notifyPowerPolicyChange(String policyId, boolean force) {
- mLastNofitiedPolicyId = policyId;
+ mLastNotifiedPolicyId = policyId;
}
@Override
@@ -1124,7 +1270,7 @@
}
public String getLastNotifiedPolicyId() {
- return mLastNofitiedPolicyId;
+ return mLastNotifiedPolicyId;
}
public String getLastDefinedPolicyId() {
@@ -1143,24 +1289,22 @@
}
private final class MockedPowerPolicyListener extends ICarPowerPolicyListener.Stub {
- private static final int NOTIFICATION_TIMEOUT_SEC = 5;
-
- private final CountDownLatch mLatch = new CountDownLatch(1);
+ private final Object mLock = new Object();
private CarPowerPolicy mCurrentPowerPolicy;
@Override
public void onPolicyChanged(CarPowerPolicy appliedPolicy,
CarPowerPolicy accumulatedPolicy) {
- mCurrentPowerPolicy = accumulatedPolicy;
- mLatch.countDown();
+ synchronized (mLock) {
+ mCurrentPowerPolicy = accumulatedPolicy;
+ }
}
+ @Nullable
public CarPowerPolicy getCurrentPowerPolicy() throws Exception {
- if (mLatch.await(NOTIFICATION_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ synchronized (mLock) {
return mCurrentPowerPolicy;
}
-
- return null;
}
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index 1a4a9a4..f3b23cc 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -210,6 +210,21 @@
}
@Test
+ public void testValidXmlWithDefaultPolicyGroup() throws Exception {
+ try (InputStream inputStream = mResources.openRawResource(
+ R.raw.valid_power_policy_default_policy_group)) {
+ mPolicyReader.readPowerPolicyFromXml(inputStream);
+ }
+
+ assertThat(mPolicyReader.getDefaultPowerPolicyGroup()).isEqualTo("mixed_policy_group");
+ }
+
+ @Test
+ public void testInvalidXml_wrongDefaultPolicyGroupId() throws Exception {
+ assertInvalidXml(R.raw.invalid_system_power_policy_incorrect_default_power_policy_group_id);
+ }
+
+ @Test
public void testDefaultPolicies() throws Exception {
assertDefaultPolicies();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
index 69f62160..c898575 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerTest.java
@@ -51,6 +51,7 @@
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.publisher.AbstractPublisher;
import com.android.car.telemetry.publisher.PublisherFactory;
+import com.android.car.telemetry.scriptexecutorinterface.BundleList;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutor;
import com.android.car.telemetry.scriptexecutorinterface.IScriptExecutorListener;
@@ -67,8 +68,10 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.PriorityBlockingQueue;
@@ -458,6 +461,24 @@
}
@Test
+ public void testScheduleNextTask_withBundleList_shouldPassData() throws Exception {
+ List<PersistableBundle> bundles = new ArrayList<>();
+ bundles.add(new PersistableBundle());
+ bundles.add(new PersistableBundle());
+ ScriptExecutionTask highPriorityTask = new ScriptExecutionTask(
+ new DataSubscriber(mDataBroker, METRICS_CONFIG_FOO, SUBSCRIBER_FOO),
+ bundles,
+ SystemClock.elapsedRealtime(),
+ TelemetryProto.Publisher.PublisherCase.STATS.getNumber());
+ mDataBroker.getTaskQueue().add(highPriorityTask);
+
+ mDataBroker.scheduleNextTask();
+
+ waitForTelemetryThreadToFinish();
+ assertThat(mFakeScriptExecutor.getInvokeScriptForBundleListCount()).isEqualTo(1);
+ }
+
+ @Test
public void testScheduleNextTask_bindScriptExecutorFailedOnce_shouldRebind()
throws Exception {
Mockito.reset(mMockContext);
@@ -698,6 +719,7 @@
private IScriptExecutorListener mListener;
private int mInvokeScriptCount = 0;
private int mInvokeScriptForLargeInputCount = 0;
+ private int mInvokeScriptForBundleListCount = 0;
private int mFailApi = 0;
private PersistableBundle mSavedState = null;
@@ -745,6 +767,19 @@
}
@Override
+ public void invokeScriptForBundleList(String scriptBody, String functionName,
+ BundleList bundleList, PersistableBundle savedState,
+ IScriptExecutorListener listener) throws RemoteException {
+ mInvokeScriptForBundleListCount++;
+ mSavedState = savedState;
+ mListener = listener;
+ if (mFailApi > 0) {
+ mFailApi--;
+ throw new RemoteException("Simulated failure");
+ }
+ }
+
+ @Override
public IBinder asBinder() {
return null;
}
@@ -800,6 +835,11 @@
return mInvokeScriptForLargeInputCount;
}
+ /** Returns number of times invokeScriptForBundleList() was called. */
+ public int getInvokeScriptForBundleListCount() {
+ return mInvokeScriptForBundleListCount;
+ }
+
/** Returns the interim data passed in invokeScript(). */
public PersistableBundle getSavedState() {
return mSavedState;
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
index 503cbea..cadfbb4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/CarTelemetrydPublisherTest.java
@@ -76,11 +76,11 @@
private static final SessionAnnotation SESSION_ANNOTATION_BEGIN_1 =
new SessionAnnotation(1, SessionController.STATE_ENTER_DRIVING_SESSION, 0, 0, "");
private static final String[] SESSION_ANNOTATION_KEYS =
- {SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID,
- SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON,
- SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_STATE,
- SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS,
- SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS};
+ {Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID,
+ Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON,
+ Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE,
+ Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS,
+ Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS};
private final FakeHandlerWrapper mFakeHandlerWrapper =
new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.IMMEDIATE);
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
index 99e42a8..e10dd1a 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/ConnectivityPublisherTest.java
@@ -195,8 +195,8 @@
return false;
}
- return savedResult.containsKey(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)
- && savedResult.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)
+ return savedResult.containsKey(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)
+ && savedResult.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)
== expectedSessionId;
}
@@ -296,13 +296,20 @@
assertThat(mDataSubscriberCell.mPushedData).hasSize(1);
PersistableBundle result = mDataSubscriberCell.get(0);
// Matches only "UID_1/TAG_1" and "UID_1/TAG_NONE" above.
- assertThat(result.getLong("startMillis")).isLessThan(mNow);
- assertThat(result.getLong("endMillis")).isGreaterThan(result.getLong("startMillis"));
- assertThat(result.getInt("size")).isEqualTo(2);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1, UID_1);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1, TAG_NONE);
- assertThat(result.getLongArray("rxBytes")).asList().containsExactly(2500L, 2502L);
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(3500L, 3502L);
+ assertThat(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS))
+ .isLessThan(mNow);
+ assertThat(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS))
+ .isGreaterThan(result.getLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS));
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(2);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID)).asList()
+ .containsExactly(UID_1, UID_1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG)).asList()
+ .containsExactly(TAG_1, TAG_NONE);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES)).asList()
+ .containsExactly(2500L, 2502L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES)).asList()
+ .containsExactly(3500L, 3502L);
}
@Test
@@ -327,12 +334,18 @@
assertThat(mDataSubscriberWifiOemManaged.mPushedData).hasSize(1);
PersistableBundle result = mDataSubscriberWifiOemManaged.get(0);
- assertThat(result.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
- assertThat(result.getInt("size")).isEqualTo(2);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_2, UID_3);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_NONE, TAG_2);
- assertThat(result.getLongArray("rxBytes")).asList().containsExactly(100L, 6L);
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(200L, 7L);
+ assertThat(result.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID))
+ .isEqualTo(1);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(2);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_2, UID_3);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_NONE, TAG_2);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+ .asList().containsExactly(100L, 6L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(200L, 7L);
}
@Test
@@ -356,13 +369,18 @@
assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
PersistableBundle result = mDataSubscriberWifi.get(0);
- assertThat(result.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
+ assertThat(result.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(1);
// Matches only UID_1.
- assertThat(result.getInt("size")).isEqualTo(1);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(30L);
- assertThat(result.getLongArray("rxBytes")).asList().containsExactly(30L);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_1);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(30L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+ .asList().containsExactly(30L);
}
@Test
@@ -392,11 +410,16 @@
PersistableBundle result = mDataSubscriberWifi.get(0);
// Only UID_1 and UID_2 are fetched, because other stats are outside
// of the time range.
- assertThat(result.getInt("size")).isEqualTo(2);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_1, UID_2);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1, TAG_1);
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(10L, 10L);
- assertThat(result.getLongArray("rxBytes")).asList().containsExactly(10L, 10L);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(2);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_1, UID_2);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_1, TAG_1);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(10L, 10L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+ .asList().containsExactly(10L, 10L);
}
@Test
@@ -441,11 +464,16 @@
assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
PersistableBundle result = mDataSubscriberWifi.get(0);
- assertThat(result.getInt("size")).isEqualTo(1);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(100L - 12L);
- assertThat(result.getLongArray("rxBytes")).asList().containsExactly(100L - 12L);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_4);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_1);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(100L - 12L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES))
+ .asList().containsExactly(100L - 12L);
}
@Test
@@ -467,11 +495,15 @@
assertThat(mDataSubscriberWifi.mPushedData).hasSize(1);
PersistableBundle result = mDataSubscriberWifi.get(0);
- assertThat(result.getInt("size")).isEqualTo(1);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_4);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_1);
// It's 200, because it subtracts previous pull 12 from (200 + 12).
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(200L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(200L);
// ==== 2nd pull.
mFakeManager.addWifiStats(UID_4, TAG_1, 1000, 1000, OEM_MANAGED_NO, mNow);
@@ -484,11 +516,30 @@
assertThat(mDataSubscriberWifi.mPushedData).hasSize(2);
result = mDataSubscriberWifi.get(1);
- assertThat(result.getInt("size")).isEqualTo(1);
- assertThat(result.getIntArray("uid")).asList().containsExactly(UID_4);
- assertThat(result.getIntArray("tag")).asList().containsExactly(TAG_1);
+ assertThat(result.getInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE))
+ .isEqualTo(1);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID))
+ .asList().containsExactly(UID_4);
+ assertThat(result.getIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG))
+ .asList().containsExactly(TAG_1);
// It's 1000, because it subtracts previous pull (200 + 12) from (200 + 12 + 1000).
- assertThat(result.getLongArray("txBytes")).asList().containsExactly(1000L);
+ assertThat(result.getLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES))
+ .asList().containsExactly(1000L);
+ }
+
+ @Test
+ public void testWhenQueryThrowsNullPointerExceptionIsCaught() {
+ mFakeManager.setSimulateFailedQuery(true);
+ mSessionControllerCallbackArgumentCaptor.getValue().onSessionStateChanged(
+ SESSION_ANNOTATION_BEGIN_1);
+
+ // querySummary gets called for each QueryParam combination, but throws
+ // NullPointerException each time, which is caught
+ assertThat(mFakeManager.getMethodCallCount("querySummary"))
+ .isEqualTo(BASELINE_PULL_COUNT);
+ // queryTaggedSummary not reached because of previous NullPointerException in querySummary
+ assertThat(mFakeManager.getMethodCallCount("queryTaggedSummary"))
+ .isEqualTo(0);
}
private static class FakeDataSubscriber extends DataSubscriber {
@@ -533,6 +584,8 @@
private final ArrayList<FakeNetworkStats.CustomBucket> mBuckets = new ArrayList<>();
private final HashMap<String, Integer> mMethodCallCount = new HashMap<>();
+ private boolean mSimulateFailedQuery = false;
+
private FakeNetworkStatsManager() {
super(/* networkStatsManager= */ null);
}
@@ -587,10 +640,17 @@
return mMethodCallCount.getOrDefault(name, 0);
}
+ public void setSimulateFailedQuery(boolean simulateFailedQuery) {
+ mSimulateFailedQuery = simulateFailedQuery;
+ }
+
@Override
@NonNull
public NetworkStatsWrapper querySummary(NetworkTemplate template, long start, long end) {
increaseMethodCall("querySummary", 1);
+ if (mSimulateFailedQuery) {
+ throw new NullPointerException();
+ }
return commonQuerySummary(false, template, start, end);
}
@@ -599,6 +659,9 @@
public NetworkStatsWrapper queryTaggedSummary(
NetworkTemplate template, long start, long end) {
increaseMethodCall("queryTaggedSummary", 1);
+ if (mSimulateFailedQuery) {
+ throw new NullPointerException();
+ }
return commonQuerySummary(true, template, start, end);
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
index 9d26b58..0ccb99c 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/MemoryPublisherTest.java
@@ -18,7 +18,6 @@
import static com.android.car.telemetry.publisher.MemoryPublisher.BUNDLE_KEY_COLLECT_INDEFINITELY;
import static com.android.car.telemetry.publisher.MemoryPublisher.BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH;
-import static com.android.car.telemetry.publisher.MemoryPublisher.DATA_BUNDLE_KEY_MEMINFO;
import static com.android.car.telemetry.publisher.MemoryPublisher.THROTTLE_MILLIS;
import static com.google.common.truth.Truth.assertThat;
@@ -32,20 +31,27 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.car.telemetry.TelemetryProto;
+import android.content.Context;
+import android.os.Debug;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.SystemClock;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
import com.android.car.telemetry.ResultStore;
import com.android.car.telemetry.databroker.DataSubscriber;
import com.android.car.telemetry.sessioncontroller.SessionAnnotation;
import com.android.car.telemetry.sessioncontroller.SessionController;
import com.android.car.test.FakeHandlerWrapper;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.google.common.collect.Range;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,6 +66,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
@RunWith(MockitoJUnitRunner.class)
public class MemoryPublisherTest {
@@ -70,13 +79,20 @@
.append("MemAvailable: 5312884 kB\n")
.append("Buffers: 224380 kB\n")
.toString();
+ private static final TelemetryProto.MemoryPublisher BASE_MEMORY_PUBLISHER =
+ TelemetryProto.MemoryPublisher.newBuilder()
+ .setReadIntervalSec(TEN_SECONDS)
+ .setMaxSnapshots(2)
+ .setMaxPendingTasks(10)
+ .build();
private static final TelemetryProto.Publisher MEMORY_PUBLISHER_TEN_SEC =
TelemetryProto.Publisher.newBuilder()
+ .setMemory(BASE_MEMORY_PUBLISHER)
+ .build();
+ private static final TelemetryProto.Publisher MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC =
+ TelemetryProto.Publisher.newBuilder()
.setMemory(
- TelemetryProto.MemoryPublisher.newBuilder()
- .setReadIntervalSec(TEN_SECONDS)
- .setMaxSnapshots(2)
- .setMaxPendingTasks(10))
+ BASE_MEMORY_PUBLISHER.toBuilder().addPackageNames("com.android.car"))
.build();
private static final TelemetryProto.Subscriber SUBSCRIBER_TEN_SEC =
TelemetryProto.Subscriber.newBuilder()
@@ -102,6 +118,10 @@
@Captor
private ArgumentCaptor<SessionController.SessionControllerCallback> mSessionCallbackCaptor;
@Mock
+ private ActivityManager mMockActivityManager;
+ @Mock
+ private Context mMockContext;
+ @Mock
private DataSubscriber mMockDataSubscriber;
@Mock
private ResultStore mMockResultStore;
@@ -119,18 +139,41 @@
when(mMockDataSubscriber.getSubscriber()).thenReturn(SUBSCRIBER_TEN_SEC);
when(mMockDataSubscriber.getMetricsConfig()).thenReturn(METRICS_CONFIG);
when(mMockDataSubscriber.getPublisherParam()).thenReturn(SUBSCRIBER_TEN_SEC.getPublisher());
+ // set up mocks for reading process meminfo
+ when(mMockContext.getSystemService(ActivityManager.class)).thenReturn(mMockActivityManager);
+ when(mMockActivityManager.getRunningAppProcesses()).thenReturn(List.of(
+ new ActivityManager.RunningAppProcessInfo(
+ "com.android.car", 123, null),
+ new ActivityManager.RunningAppProcessInfo(
+ "com.android.car.scriptexecutor", 456, null)));
+ when(mMockActivityManager.getProcessMemoryInfo(any())).thenAnswer(i -> {
+ int length = ((int[]) i.getArguments()[0]).length;
+ Debug.MemoryInfo[] mis = new Debug.MemoryInfo[length];
+ Debug.MemoryInfo mi = new Debug.MemoryInfo();
+ Arrays.fill(mis, mi);
+ return mis;
+ });
+ MockContentResolver mockContentResolver = new MockContentResolver();
+ mockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mMockContext.getContentResolver()).thenReturn(mockContentResolver);
// create MemoryPublisher
mPublisher = createPublisher(mTempFile.toPath());
verify(mMockSessionController).registerCallback(mSessionCallbackCaptor.capture());
}
+ @After
+ public void tearDown() {
+ mPublisher.removeAllDataSubscribers();
+ }
+
/**
* Emulates a restart by creating a new MemoryPublisher. StatsManager and PersistableBundle
* stays the same.
*/
private MemoryPublisher createPublisher(Path meminfoPath) {
return new MemoryPublisher(
+ mMockContext,
mFakePublisherListener,
mFakeHandlerWrapper.getMockHandler(),
mMockResultStore,
@@ -139,16 +182,141 @@
}
@Test
- public void testAddDataSubscriber_pullsMeminfo() {
+ public void testAddDataSubscriber_whenNoPackageName_pullsDeviceMeminfo() {
mPublisher.addDataSubscriber(mMockDataSubscriber);
assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isTrue();
- verify(mMockDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getString(DATA_BUNDLE_KEY_MEMINFO))
+ verify(mMockDataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+ assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
+ .containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+ Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+ assertThat(mBundleCaptor.getValue().getString(Constants.MEMORY_BUNDLE_KEY_MEMINFO))
.isEqualTo(FAKE_MEMINFO);
}
@Test
+ public void testAddDataSubscriber_whenMatchingPackageName_pullsDeviceAndProcessMeminfo() {
+ DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+ when(dataSubscriber.getSubscriber()).thenReturn(
+ SUBSCRIBER_TEN_SEC.toBuilder()
+ .setPublisher(MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC).build());
+ when(dataSubscriber.getPublisherParam()).thenReturn(
+ MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC);
+
+ mPublisher.addDataSubscriber(dataSubscriber);
+
+ assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+ verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+ PersistableBundle bundle = mBundleCaptor.getValue();
+ assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+ Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
+ "com.android.car:0:com.android.car");
+ PersistableBundle processBundle = bundle.getPersistableBundle(
+ "com.android.car:0:com.android.car");
+ assertThat(processBundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+ "mem.summary.java-heap",
+ "mem.summary.total-pss",
+ "mem.summary.private-other",
+ "mem.summary.native-heap",
+ "mem.summary.stack",
+ "mem.summary.system",
+ "mem.summary.code",
+ "mem.summary.graphics",
+ "mem.summary.total-swap");
+ }
+
+ @Test
+ public void testAddDataSubscriber_multipleMatchingPackageName_pullsDeviceAndProcessMeminfo() {
+ // setup processes
+ ActivityManager.RunningAppProcessInfo process1 = new ActivityManager.RunningAppProcessInfo(
+ "com.android.car", 111, null);
+ process1.uid = 12345;
+ ActivityManager.RunningAppProcessInfo process2 = new ActivityManager.RunningAppProcessInfo(
+ "com.android.car", 222, null);
+ process2.uid = 67890;
+ when(mMockActivityManager.getRunningAppProcesses()).thenReturn(List.of(process1, process2));
+ // set up subscribers that listen for process memory
+ DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+ when(dataSubscriber.getSubscriber()).thenReturn(
+ SUBSCRIBER_TEN_SEC.toBuilder()
+ .setPublisher(MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC).build());
+ when(dataSubscriber.getPublisherParam()).thenReturn(
+ MEMORY_PUBLISHER_PROCESS_MEMORY_TEN_SEC);
+
+ mPublisher.addDataSubscriber(dataSubscriber);
+
+ assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+ verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+ PersistableBundle bundle = mBundleCaptor.getValue();
+ assertThat(bundle.keySet().stream().collect(Collectors.toList())).containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+ Constants.MEMORY_BUNDLE_KEY_TIMESTAMP,
+ "com.android.car:12345:com.android.car",
+ "com.android.car:67890:com.android.car");
+ PersistableBundle processBundle1 = bundle.getPersistableBundle(
+ "com.android.car:12345:com.android.car");
+ PersistableBundle processBundle2 = bundle.getPersistableBundle(
+ "com.android.car:67890:com.android.car");
+ assertThat(processBundle1.keySet().stream().collect(Collectors.toList())).containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+ "mem.summary.java-heap",
+ "mem.summary.total-pss",
+ "mem.summary.private-other",
+ "mem.summary.native-heap",
+ "mem.summary.stack",
+ "mem.summary.system",
+ "mem.summary.code",
+ "mem.summary.graphics",
+ "mem.summary.total-swap");
+ assertThat(processBundle2.keySet().stream().collect(Collectors.toList())).containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SWAPPABLE_PSS,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_DIRTY,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_PRIVATE_CLEAN,
+ Constants.MEMORY_BUNDLE_KEY_TOTAL_SHARED_CLEAN,
+ "mem.summary.java-heap",
+ "mem.summary.total-pss",
+ "mem.summary.private-other",
+ "mem.summary.native-heap",
+ "mem.summary.stack",
+ "mem.summary.system",
+ "mem.summary.code",
+ "mem.summary.graphics",
+ "mem.summary.total-swap");
+ }
+
+ @Test
+ public void testAddDataSubscriber_whenPackageNameNotFound_doesNotPullProcessMeminfo() {
+ String packageName = "com.example.does.not.exist";
+ DataSubscriber dataSubscriber = mock(DataSubscriber.class);
+ TelemetryProto.Publisher publisher = TelemetryProto.Publisher.newBuilder().setMemory(
+ BASE_MEMORY_PUBLISHER.toBuilder().addPackageNames(packageName)).build();
+ when(dataSubscriber.getSubscriber()).thenReturn(
+ SUBSCRIBER_TEN_SEC.toBuilder().setPublisher(publisher).build());
+ when(dataSubscriber.getPublisherParam()).thenReturn(publisher);
+
+ mPublisher.addDataSubscriber(dataSubscriber);
+
+ assertThat(mPublisher.hasDataSubscriber(dataSubscriber)).isTrue();
+ verify(dataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
+ assertThat(mBundleCaptor.getValue().keySet().stream().collect(Collectors.toList()))
+ .containsExactly(
+ Constants.MEMORY_BUNDLE_KEY_MEMINFO,
+ Constants.MEMORY_BUNDLE_KEY_TIMESTAMP);
+ }
+
+ @Test
public void testAddDataSubscriber_annotatesWithDrivingSessionData() {
SessionAnnotation sessionAnnotation = new SessionAnnotation(
2, SessionController.STATE_ENTER_DRIVING_SESSION, 123, 1234, "reboot");
@@ -156,11 +324,10 @@
mSessionCallbackCaptor.getValue().onSessionStateChanged(sessionAnnotation);
mPublisher.addDataSubscriber(mMockDataSubscriber);
- verify(mMockDataSubscriber).push(mBundleCaptor.capture());
+ verify(mMockDataSubscriber).push(mBundleCaptor.capture(), anyBoolean());
PersistableBundle report = mBundleCaptor.getValue();
- assertThat(report.getString(DATA_BUNDLE_KEY_MEMINFO)).isEqualTo(FAKE_MEMINFO);
- assertThat(report.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(2);
- assertThat(report.getString(SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON))
+ assertThat(report.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(2);
+ assertThat(report.getString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON))
.isEqualTo("reboot");
}
@@ -213,7 +380,7 @@
// verify the MetricsConfig is removed
assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
- verify(mMockDataSubscriber, times(2)).push(any());
+ verify(mMockDataSubscriber, times(2)).push(any(), anyBoolean());
assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
}
@@ -264,24 +431,6 @@
}
@Test
- public void testReadMeminfo_whenPreviousStateExists_shouldContinueFromPrevious() {
- PersistableBundle publisherState = new PersistableBundle();
- publisherState.putInt(BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH, 1);
- publisherState.putBoolean(BUNDLE_KEY_COLLECT_INDEFINITELY, false);
- when(mMockResultStore.getPublisherData(any(), anyBoolean())).thenReturn(publisherState);
- mPublisher = createPublisher(mTempFile.toPath());
-
- // since there is 1 snapshot left, this is the last read and the subscriber will be removed
- mPublisher.addDataSubscriber(mMockDataSubscriber);
- mFakeHandlerWrapper.dispatchQueuedMessages();
-
- assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
- assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
- verify(mMockResultStore).removePublisherData(eq(MemoryPublisher.class.getSimpleName()));
- assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
- }
-
- @Test
public void testRemoveDataSubscriber_ifDoesNotMatch_keepsSubscriber() {
mPublisher.addDataSubscriber(mMockDataSubscriber);
DataSubscriber differentSubscriber = Mockito.mock(DataSubscriber.class);
@@ -305,7 +454,7 @@
@Test
public void testReadMeminfo_shouldThrottlePublisher() {
// 100 MemoryPublisher-related tasks pending script execution > the throttle limit
- when(mMockDataSubscriber.push(any())).thenReturn(100);
+ when(mMockDataSubscriber.push(any(), anyBoolean())).thenReturn(100);
mPublisher.addDataSubscriber(mMockDataSubscriber);
@@ -315,6 +464,24 @@
assertThatMessageIsScheduledWithGivenDelay(message, THROTTLE_MILLIS);
}
+ @Test
+ public void testReadMeminfo_whenPreviousStateExists_shouldContinueFromPrevious() {
+ PersistableBundle publisherState = new PersistableBundle();
+ publisherState.putInt(BUNDLE_KEY_NUM_SNAPSHOTS_UNTIL_FINISH, 1);
+ publisherState.putBoolean(BUNDLE_KEY_COLLECT_INDEFINITELY, false);
+ when(mMockResultStore.getPublisherData(any(), anyBoolean())).thenReturn(publisherState);
+ mPublisher = createPublisher(mTempFile.toPath());
+
+ // since there is 1 snapshot left, this is the last read and the subscriber will be removed
+ mPublisher.addDataSubscriber(mMockDataSubscriber);
+ mFakeHandlerWrapper.dispatchQueuedMessages();
+
+ assertThat(mPublisher.hasDataSubscriber(mMockDataSubscriber)).isFalse();
+ assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(0);
+ verify(mMockResultStore).removePublisherData(eq(MemoryPublisher.class.getSimpleName()));
+ assertThat(mFakePublisherListener.mFinishedConfig).isEqualTo(METRICS_CONFIG);
+ }
+
private static void assertThatMessageIsScheduledWithGivenDelay(Message msg, long delayMillis) {
long expectedTimeMillis = SystemClock.uptimeMillis() + delayMillis;
long deltaMillis = 1000; // +/- 1 seconds is good enough for testing
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
index f8f5f6d..d3858e4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/StatsPublisherTest.java
@@ -387,8 +387,7 @@
assertThat(mFakeHandlerWrapper.getQueuedMessages()).hasSize(1);
Message msg = mFakeHandlerWrapper.getQueuedMessages().get(0);
- long expectedPullPeriodMillis = 10 * 60 * 1000; // 10 minutes
- assertThatMessageIsScheduledWithGivenDelay(msg, expectedPullPeriodMillis);
+ assertThatMessageIsScheduledWithGivenDelay(msg, 0);
}
@Test
@@ -454,17 +453,17 @@
verify(subscriber1).push(mBundleCaptor.capture(), anyBoolean());
PersistableBundle bundle1 = mBundleCaptor.getValue();
- assertThat(bundle1.getLongArray("elapsed_timestamp_nanos"))
+ assertThat(bundle1.getLongArray("stats.elapsed_timestamp_nanos"))
.asList().containsExactly(99999999L);
- assertThat(bundle1.getIntArray("uid")).asList().containsExactly(1000);
- assertThat(Arrays.asList(bundle1.getStringArray("activity_name")))
+ assertThat(bundle1.getIntArray("stats.uid")).asList().containsExactly(1000);
+ assertThat(Arrays.asList(bundle1.getStringArray("stats.activity_name")))
.containsExactly("activityName");
- assertThat(bundle1.getLongArray("rss_in_bytes")).asList().containsExactly(1234L);
+ assertThat(bundle1.getLongArray("stats.rss_in_bytes")).asList().containsExactly(1234L);
verify(subscriber2).push(mBundleCaptor.capture(), anyBoolean());
PersistableBundle bundle2 = mBundleCaptor.getValue();
- assertThat(bundle2.getIntArray("uid")).asList().containsExactly(234);
- assertThat(bundle2.getLongArray("rss_in_bytes")).asList().containsExactly(4567L);
- assertThat(bundle2.getLongArray("elapsed_timestamp_nanos"))
+ assertThat(bundle2.getIntArray("stats.uid")).asList().containsExactly(234);
+ assertThat(bundle2.getLongArray("stats.rss_in_bytes")).asList().containsExactly(4567L);
+ assertThat(bundle2.getLongArray("stats.elapsed_timestamp_nanos"))
.asList().containsExactly(445678901L);
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
index 2536327..2905dc4 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/VehiclePropertyPublisherTest.java
@@ -18,16 +18,6 @@
import static android.car.hardware.property.CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BOOLEAN_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_BYTE_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_FLOAT_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_INT_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_ARRAY_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_LONG_KEY;
-import static com.android.car.telemetry.publisher.VehiclePropertyPublisher.BUNDLE_STRING_KEY;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
@@ -81,6 +71,7 @@
private static final int PROP_BYTES_ID = 0x00700000;
private static final int PROP_MIXED_ID = 0x00e00000;
private static final int AREA_ID = 20;
+ private static final int STATUS = 0;
private static final float PROP_READ_RATE = 0.0f;
private static final CarPropertyEvent PROP_STRING_EVENT =
new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
@@ -234,7 +225,7 @@
CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_WRITE).build();
private final FakeHandlerWrapper mFakeHandlerWrapper =
- new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.IMMEDIATE);
+ new FakeHandlerWrapper(Looper.getMainLooper(), FakeHandlerWrapper.Mode.QUEUEING);
private final FakePublisherListener mFakePublisherListener = new FakePublisherListener();
@Mock
@@ -264,6 +255,8 @@
private ArgumentCaptor<ICarPropertyEventListener> mCarPropertyCallbackCaptor;
@Captor
private ArgumentCaptor<PersistableBundle> mBundleCaptor;
+ @Captor
+ private ArgumentCaptor<List<PersistableBundle>> mBundleListCaptor;
private VehiclePropertyPublisher mVehiclePropertyPublisher;
@@ -384,18 +377,24 @@
public void testOnNewCarPropertyEvent_pushesValueToDataSubscriber() throws Exception {
doNothing().when(mMockCarPropertyService).registerListener(
anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+ mVehiclePropertyPublisher.setBatchIntervalMillis(0L);
mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
mCarPropertyCallbackCaptor.getValue().onEvent(Collections.singletonList(PROP_INT_EVENT));
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch immediately posted messages
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch delay posted messages
- verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+ verify(mMockIntDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().size()).isEqualTo(1);
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
}
@Test
public void testOnNewCarPropertyEvent_parsesValueCorrectly() throws Exception {
doNothing().when(mMockCarPropertyService).registerListener(
anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+ mVehiclePropertyPublisher.setBatchIntervalMillis(1L);
mVehiclePropertyPublisher.addDataSubscriber(mMockStringDataSubscriber);
mVehiclePropertyPublisher.addDataSubscriber(mMockBoolDataSubscriber);
mVehiclePropertyPublisher.addDataSubscriber(mMockIntDataSubscriber);
@@ -407,6 +406,7 @@
mVehiclePropertyPublisher.addDataSubscriber(mMockBytesDataSubscriber);
mVehiclePropertyPublisher.addDataSubscriber(mMockMixedDataSubscriber);
ICarPropertyEventListener eventListener = mCarPropertyCallbackCaptor.getValue();
+
eventListener.onEvent(Collections.singletonList(PROP_STRING_EVENT));
eventListener.onEvent(Collections.singletonList(PROP_BOOLEAN_EVENT));
eventListener.onEvent(Collections.singletonList(PROP_INT_EVENT));
@@ -417,51 +417,107 @@
eventListener.onEvent(Collections.singletonList(PROP_FLOAT_VEC_EVENT));
eventListener.onEvent(Collections.singletonList(PROP_BYTES_EVENT));
eventListener.onEvent(Collections.singletonList(PROP_MIXED_EVENT));
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch immediately posted messages
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch delay posted messages
- verify(mMockStringDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("hi");
+ verify(mMockStringDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+ .isEqualTo("hi");
- verify(mMockBoolDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
+ verify(mMockBoolDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN)).isTrue();
- verify(mMockIntDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
+ verify(mMockIntDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
- verify(mMockIntVecDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+ verify(mMockIntVecDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY))
.isEqualTo(new int[] {1, 2});
- verify(mMockLongDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(10L);
+ verify(mMockLongDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG)).isEqualTo(10L);
- verify(mMockLongVecDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+ verify(mMockLongVecDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY))
.isEqualTo(new long[] {10L, 20L});
- verify(mMockFloatDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(1d);
+ verify(mMockFloatDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT)).isEqualTo(1d);
- verify(mMockFloatVecDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+ verify(mMockFloatVecDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY))
.isEqualTo(new double[] {1d, 2d});
- verify(mMockBytesDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+ verify(mMockBytesDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY))
.isEqualTo(new String(new byte[] {(byte) 1, (byte) 2}, StandardCharsets.UTF_8));
- verify(mMockMixedDataSubscriber).push(mBundleCaptor.capture());
- assertThat(mBundleCaptor.getValue().getString(BUNDLE_STRING_KEY)).isEqualTo("test");
- assertThat(mBundleCaptor.getValue().getBoolean(BUNDLE_BOOLEAN_KEY)).isTrue();
- assertThat(mBundleCaptor.getValue().getInt(BUNDLE_INT_KEY)).isEqualTo(1);
- assertThat(mBundleCaptor.getValue().getIntArray(BUNDLE_INT_ARRAY_KEY))
+ verify(mMockMixedDataSubscriber).push(mBundleListCaptor.capture());
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+ .isEqualTo("test");
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getBoolean(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BOOLEAN)).isTrue();
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getInt(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT)).isEqualTo(1);
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getIntArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_INT_ARRAY))
.isEqualTo(new int[] {2, 3, 4});
- assertThat(mBundleCaptor.getValue().getLong(BUNDLE_LONG_KEY)).isEqualTo(2L);
- assertThat(mBundleCaptor.getValue().getLongArray(BUNDLE_LONG_ARRAY_KEY))
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getLong(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG)).isEqualTo(2L);
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getLongArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_LONG_ARRAY))
.isEqualTo(new long[] {5L, 6L});
- assertThat(mBundleCaptor.getValue().getDouble(BUNDLE_FLOAT_KEY)).isEqualTo(3d);
- assertThat(mBundleCaptor.getValue().getDoubleArray(BUNDLE_FLOAT_ARRAY_KEY))
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getDouble(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT)).isEqualTo(3d);
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getDoubleArray(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_FLOAT_ARRAY))
.isEqualTo(new double[] {7d, 8d});
- assertThat(mBundleCaptor.getValue().getString(BUNDLE_BYTE_ARRAY_KEY))
+ assertThat(mBundleListCaptor.getValue().get(0)
+ .getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_BYTE_ARRAY))
.isEqualTo(new String(new byte[] {(byte) 5, (byte) 6}, StandardCharsets.UTF_8));
}
+
+ @Test
+ public void testOnNewCarPropertyEvents_batchIsPushedAfterDelay() throws Exception {
+ doNothing().when(mMockCarPropertyService).registerListener(
+ anyInt(), anyFloat(), mCarPropertyCallbackCaptor.capture());
+ mVehiclePropertyPublisher.setBatchIntervalMillis(10L); // Batch interval 10 milliseconds
+ mVehiclePropertyPublisher.addDataSubscriber(mMockStringDataSubscriber);
+ ICarPropertyEventListener eventListener = mCarPropertyCallbackCaptor.getValue();
+ CarPropertyEvent propEvent1 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 0L,
+ "first"));
+ CarPropertyEvent propEvent2 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 5L,
+ "second"));
+ CarPropertyEvent propEvent3 = new CarPropertyEvent(PROPERTY_EVENT_PROPERTY_CHANGE,
+ new CarPropertyValue<>(PROP_STRING_ID, AREA_ID, STATUS, /* timestamp= */ 7L,
+ "third"));
+
+ eventListener.onEvent(Collections.singletonList(propEvent1));
+ eventListener.onEvent(Collections.singletonList(propEvent2));
+ eventListener.onEvent(Collections.singletonList(propEvent3));
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch immediately posted messages
+ mFakeHandlerWrapper.dispatchQueuedMessages(); // Dispatch delay posted messages
+
+ verify(mMockStringDataSubscriber).push(mBundleListCaptor.capture());
+ List<PersistableBundle> bundleList = mBundleListCaptor.getValue();
+ assertThat(bundleList.size()).isEqualTo(3);
+ assertThat(bundleList.get(0).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+ .isEqualTo("first");
+ assertThat(bundleList.get(1).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+ .isEqualTo("second");
+ assertThat(bundleList.get(2).getString(Constants.VEHICLE_PROPERTY_BUNDLE_KEY_STRING))
+ .isEqualTo("third");
+ }
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
index ced410b..1f2e2f6 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/net/RefinedStatsTest.java
@@ -28,6 +28,7 @@
import android.os.PersistableBundle;
import com.android.car.telemetry.UidPackageMapper;
+import com.android.car.telemetry.publisher.Constants;
import com.android.internal.util.FastXmlSerializer;
import org.junit.Before;
@@ -79,14 +80,15 @@
PersistableBundle result = mRefinedStats.toPersistableBundle(mMockUidMapper);
PersistableBundle expected = new PersistableBundle();
- expected.putLong("startMillis", 10_000);
- expected.putLong("endMillis", 20_000);
- expected.putInt("size", 2);
- expected.putIntArray("uid", new int[] {UID_0, UID_1});
- expected.putStringArray("packages", new String[] {"pkg1,pkg2", "pkg1,pkg2"});
- expected.putIntArray("tag", new int[] {TAG_1, TAG_NONE});
- expected.putLongArray("rxBytes", new long[] {14096, 4095});
- expected.putLongArray("txBytes", new long[] {12048, 2047});
+ expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, 10_000);
+ expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, 20_000);
+ expected.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, 2);
+ expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID, new int[] {UID_0, UID_1});
+ expected.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES,
+ new String[] {"pkg1,pkg2", "pkg1,pkg2"});
+ expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG, new int[] {TAG_1, TAG_NONE});
+ expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES, new long[] {14096, 4095});
+ expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES, new long[] {12048, 2047});
assertThat(bundleToXml(result)).isEqualTo(bundleToXml(expected));
}
@@ -122,15 +124,21 @@
RefinedStats diff = RefinedStats.subtract(mRefinedStats, other);
PersistableBundle expected = new PersistableBundle();
- expected.putLong("startMillis", 10_000);
- expected.putLong("endMillis", 20_000);
- expected.putInt("size", 3); // the same size as "mRefinedStats"
- expected.putIntArray("uid", new int[] {UID_1, UID_1, UID_2});
- expected.putStringArray("packages", new String[] {"pkg1,pkg2", "pkg1,pkg2", "pkg1,pkg2"});
- expected.putIntArray("tag", new int[] {TAG_NONE, TAG_1, TAG_NONE});
+ expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_START_MILLIS, 10_000);
+ expected.putLong(Constants.CONNECTIVITY_BUNDLE_KEY_END_MILLIS, 20_000);
+ // the same size as "mRefinedStats"
+ expected.putInt(Constants.CONNECTIVITY_BUNDLE_KEY_SIZE, 3);
+ expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_UID,
+ new int[] {UID_1, UID_1, UID_2});
+ expected.putStringArray(Constants.CONNECTIVITY_BUNDLE_KEY_PACKAGES,
+ new String[] {"pkg1,pkg2", "pkg1,pkg2", "pkg1,pkg2"});
+ expected.putIntArray(Constants.CONNECTIVITY_BUNDLE_KEY_TAG,
+ new int[] {TAG_NONE, TAG_1, TAG_NONE});
// Handles negative values too (hence 0).
- expected.putLongArray("rxBytes", new long[] {4090, 0, 4096});
- expected.putLongArray("txBytes", new long[] {2040, 0, 2048});
+ expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_RX_BYTES,
+ new long[] {4090, 0, 4096});
+ expected.putLongArray(Constants.CONNECTIVITY_BUNDLE_KEY_TX_BYTES,
+ new long[] {2040, 0, 2048});
assertThat(bundleToXml(diff.toPersistableBundle(mMockUidMapper)))
.isEqualTo(bundleToXml(expected));
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
index 8efaf1b..5a9ddd7 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ActivityForegroundStateChangedConverterTest.java
@@ -20,6 +20,7 @@
import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.PKG_NAME_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.STATE_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ActivityForegroundStateChanged.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -105,15 +106,18 @@
dimensionsValuesList, HASH_STR_MAP);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PKG_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PKG_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("package.name.1", "package.name.2").inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(CLASS_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ CLASS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("className1", "className2").inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(STATE_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(STATE_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(0, 1).inOrder(); // States background=0 and foreground=1
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
index f776da9..9cfa917 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AnrOccurredConverterTest.java
@@ -20,6 +20,7 @@
import static com.android.car.telemetry.AtomsProto.ANROccurred.PACKAGE_NAME_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ANROccurred.REASON_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ANROccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -78,14 +79,19 @@
PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PACKAGE_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PACKAGE_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
- assertThat(bundle.getStringArray(accessorMap.get(REASON_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(REASON_FIELD_NUMBER).getFieldName()))
.asList().containsExactly("test1", "test2").inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ERROR_SOURCE_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(1, 2).inOrder(); // DATA_APP=1, SYSTEM_APP=2
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
index 9ceef70..b925af0 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppCrashOccurredConverterTest.java
@@ -20,6 +20,7 @@
import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.PACKAGE_NAME_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.PID_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppCrashOccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -77,13 +78,19 @@
PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(12345, 67890).inOrder();
- assertThat(bundle.getStringArray(accessorMap.get(PACKAGE_NAME_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PACKAGE_NAME_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ERROR_SOURCE_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(1, 2).inOrder(); // DATA_APP=1, SYSTEM_APP=2
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
index c2346a1..30b5f21 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AppStartMemoryStateCapturedConverterTest.java
@@ -24,6 +24,7 @@
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.SWAP_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -119,24 +120,36 @@
dimensionsValuesList, HASH_STR_MAP);
assertThat(bundle.size()).isEqualTo(8);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PROCESS_NAME_FIELD_NUMBER)
+ .getFieldName())))
.containsExactly("process.name.1", "process.name.2").inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER)
+ .getFieldName())))
.containsExactly("activityName1", "activityName2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(59L, 99L).inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(34L, 55L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(1234L, 2345L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(234L, 345L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(111L, 222L).inOrder();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
index 752cd36..51dd912 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/AtomListConverterTest.java
@@ -16,6 +16,8 @@
package com.android.car.telemetry.publisher.statsconverters;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
import static com.google.common.truth.Truth.assertThat;
import android.os.PersistableBundle;
@@ -60,15 +62,17 @@
assertThat(bundle.size()).isEqualTo(3);
assertThat(bundle.getIntArray(
- accessorMap.get(AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 1100).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
- .getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
+ .getFieldName())))
.containsExactly("activityName1", "activityName2").inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER)
- .getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 2345L).inOrder();
}
@@ -96,13 +100,16 @@
assertThat(bundle.size()).isEqualTo(3);
assertThat(bundle.getIntArray(
- accessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER)
+ .getFieldName()))
.asList().containsExactly(1000, 1100).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("processName1", "processName2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(
- ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 2345L).inOrder();
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
index da486d8..cd7da4b 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ConfigMetricsReportListConverterTest.java
@@ -16,6 +16,9 @@
package com.android.car.telemetry.publisher.statsconverters;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
import static com.google.common.truth.Truth.assertThat;
import android.os.PersistableBundle;
@@ -101,33 +104,34 @@
assertThat(new ArrayList<Long>(map.keySet())).containsExactly(12345L, 23456L);
PersistableBundle eventBundle = map.get(12345L);
- assertThat(eventBundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(eventBundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(99999999L);
assertThat(eventBundle.getIntArray(
- appMemAccessorMap.get(AppStartMemoryStateCaptured.UID_FIELD_NUMBER)
- .getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+ AppStartMemoryStateCaptured.UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000);
assertThat(Arrays.asList(eventBundle.getStringArray(
- appMemAccessorMap.get(AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER)
- .getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+ AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("activityName");
assertThat(eventBundle.getLongArray(
- appMemAccessorMap.get(AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER)
- .getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + appMemAccessorMap.get(
+ AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L);
PersistableBundle gaugeBundle = map.get(23456L);
assertThat(gaugeBundle.getIntArray(
- procMemAccessorMap.get(ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+ ProcessMemoryState.UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(234);
assertThat(Arrays.asList(gaugeBundle.getStringArray(
- procMemAccessorMap.get(ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER)
- .getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+ ProcessMemoryState.PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("process.name");
assertThat(gaugeBundle.getLongArray(
- procMemAccessorMap.get(ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER)
- .getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + procMemAccessorMap.get(
+ ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(4567L);
- assertThat(gaugeBundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(gaugeBundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(445678901L);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
index 5cb41c0..2b4ee7b 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/EventMetricDataConverterTest.java
@@ -19,6 +19,8 @@
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.ACTIVITY_NAME_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.RSS_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.AppStartMemoryStateCaptured.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -68,14 +70,18 @@
PersistableBundle bundle = EventMetricDataConverter.convertEventDataList(eventDataList);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(12345678L, 23456789L).inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 1100).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("activityName1", "activityName2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 2345L).inOrder();
}
@@ -112,14 +118,18 @@
PersistableBundle bundle = EventMetricDataConverter.convertEventDataList(eventDataList);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getLongArray(EventMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(12345678L, 12345679L, 23456789L).inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 1000, 1100).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ACTIVITY_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("activityName1", "activityName1", "activityName2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 1234L, 2345L).inOrder();
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
index 4053135..e80a29d 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/GaugeMetricDataConverterTest.java
@@ -21,6 +21,8 @@
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.SWAP_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -105,19 +107,26 @@
// For each atom 2 fields were set, additionally 3 fields were encoded in dimension values,
// and 1 elapsed time array, so 6 arrays are expected in the bundle.
assertThat(bundle.size()).isEqualTo(6);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(123, 123, 123, 234).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("process.name.1", "process.name.1",
"process.name.1", "process.name.2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000L, 1100L, 1200L, 1300L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 2345L, 3456L, 4567L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(11111111L, 11111111L, 11111111L, 22222222L).inOrder();
- assertThat(bundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(12345678L, 23456789L, 34567890L, 445678901L).inOrder();
}
@@ -190,20 +199,27 @@
// For each atom 2 fields were set, additionally 3 fields were encoded in dimension values,
// and 1 elapsed time array, so 6 arrays are expected in the bundle.
assertThat(bundle.size()).isEqualTo(6);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(123, 123, 123, 123, 123, 234).inOrder();
assertThat(Arrays.asList(bundle.getStringArray(
- accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("process.name.1", "process.name.1", "process.name.1",
"process.name.1", "process.name.1", "process.name.2").inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000L, 1000L, 1100L, 1200L, 1200L, 1300L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 1234L, 2345L, 3456L, 3456L, 4567L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(
11111111L, 11111111L, 11111111L, 11111111L, 11111111L, 22222222L).inOrder();
- assertThat(bundle.getLongArray(GaugeMetricDataConverter.ELAPSED_TIME_NANOS))
+ assertThat(bundle.getLongArray(STATS_BUNDLE_KEY_ELAPSED_TIMESTAMP))
.asList().containsExactly(
12345678L, 12345679L, 23456789L, 34567890L, 34567899L, 445678901L).inOrder();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
index 75c1bf6..a0faf78 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessCpuTimeConverterTest.java
@@ -20,6 +20,7 @@
import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.SYSTEM_TIME_MILLIS_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.UID_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessCpuTime.USER_TIME_MILLIS_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -102,16 +103,20 @@
dimensionsValuesList, HASH_STR_MAP);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("process.name.1", "process.name.2").inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(USER_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ USER_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(234L, 345L).inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(SYSTEM_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ SYSTEM_TIME_MILLIS_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(111L, 222L).inOrder();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java
new file mode 100644
index 0000000..715830e
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemorySnapshotConverterTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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.publisher.statsconverters;
+
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.ANON_RSS_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.GPU_MEMORY_KB_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.HAS_FOREGROUND_SERVICES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.OOM_SCORE_ADJ_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.PID_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.PROCESS_NAME_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.RSS_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.SWAP_IN_KILOBYTES_FIELD_NUMBER;
+import static com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.os.PersistableBundle;
+import android.util.SparseArray;
+
+import com.android.car.telemetry.AtomsProto.Atom;
+import com.android.car.telemetry.AtomsProto.ProcessMemorySnapshot;
+import com.android.car.telemetry.StatsLogProto.DimensionsValue;
+import com.android.car.telemetry.publisher.HashUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class ProcessMemorySnapshotConverterTest {
+ private static final Atom ATOM_A =
+ Atom.newBuilder()
+ .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+ .setPid(88)
+ .setOomScoreAdj(100)
+ .setRssInKilobytes(1234)
+ .setAnonRssInKilobytes(99)
+ .setSwapInKilobytes(101)
+ .setAnonRssAndSwapInKilobytes(200)
+ .setGpuMemoryKb(0)
+ .setHasForegroundServices(true))
+ .build();
+
+ private static final Atom ATOM_B =
+ Atom.newBuilder()
+ .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+ .setPid(99)
+ .setOomScoreAdj(200)
+ .setRssInKilobytes(6666)
+ .setAnonRssInKilobytes(100)
+ .setSwapInKilobytes(100)
+ .setAnonRssAndSwapInKilobytes(200)
+ .setGpuMemoryKb(1)
+ .setHasForegroundServices(false))
+ .build();
+
+ private static final Atom ATOM_MISMATCH =
+ Atom.newBuilder()
+ .setProcessMemorySnapshot(ProcessMemorySnapshot.newBuilder()
+ // Some fields are not set, creating mismatch with above atoms
+ .setSwapInKilobytes(333))
+ .build();
+
+ private static final List<Integer> DIM_FIELDS_IDS = Arrays.asList(1, 2);
+ private static final Long HASH_1 = HashUtils.murmur2Hash64("process.name.1");
+ private static final Long HASH_2 = HashUtils.murmur2Hash64("process.name.2");
+ private static final Map<Long, String> HASH_STR_MAP = Map.of(
+ HASH_1, "process.name.1",
+ HASH_2, "process.name.2");
+
+ private static final List<DimensionsValue> DV_PAIR_A =
+ Arrays.asList(
+ DimensionsValue.newBuilder().setValueInt(1000).build(),
+ DimensionsValue.newBuilder().setValueStrHash(HASH_1).build());
+
+ private static final List<DimensionsValue> DV_PAIR_B =
+ Arrays.asList(
+ DimensionsValue.newBuilder().setValueInt(2000).build(),
+ DimensionsValue.newBuilder().setValueStrHash(HASH_2).build());
+
+ private static final List<DimensionsValue> DV_PAIR_MALFORMED =
+ Arrays.asList(
+ DimensionsValue.newBuilder().setValueInt(3000).build(),
+ // Wrong format since leaf level dimension value should set value, not field
+ DimensionsValue.newBuilder().setField(3).build());
+
+ // Subject of the test.
+ private ProcessMemorySnapshotConverter mConverter = new ProcessMemorySnapshotConverter();
+
+ @Test
+ public void testConvertAtomsListWithDimensionValues_putsCorrectDataToPersistableBundle()
+ throws StatsConversionException {
+ List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_B);
+ List<List<DimensionsValue>> dimensionsValuesList = Arrays.asList(DV_PAIR_A, DV_PAIR_B);
+ SparseArray<AtomFieldAccessor<ProcessMemorySnapshot, ?>> accessorMap =
+ mConverter.getAtomFieldAccessorMap();
+
+ PersistableBundle bundle = mConverter.convert(atomsList, DIM_FIELDS_IDS,
+ dimensionsValuesList, HASH_STR_MAP);
+
+ assertThat(bundle.size()).isEqualTo(10);
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(1000, 2000).inOrder();
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ .containsExactly("process.name.1", "process.name.2").inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PID_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(88, 99);
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ OOM_SCORE_ADJ_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(100, 200).inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(1234, 6666).inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ANON_RSS_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(99, 100).inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ SWAP_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(101, 100).inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ANON_RSS_AND_SWAP_IN_KILOBYTES_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(200, 200).inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ GPU_MEMORY_KB_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(0, 1).inOrder();
+ assertThat(bundle.getBooleanArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ HAS_FOREGROUND_SERVICES_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(true, false).inOrder();
+ }
+
+ @Test
+ public void testAtomSetFieldInconsistency_throwsException() {
+ List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_MISMATCH);
+ List<List<DimensionsValue>> dimensionsValuesList = Arrays.asList(DV_PAIR_A, DV_PAIR_B);
+
+ assertThrows(
+ StatsConversionException.class,
+ () -> mConverter.convert(
+ atomsList,
+ DIM_FIELDS_IDS,
+ dimensionsValuesList,
+ HASH_STR_MAP));
+ }
+
+ @Test
+ public void testMalformedDimensionValue_throwsException() {
+ List<Atom> atomsList = Arrays.asList(ATOM_A, ATOM_B);
+ List<List<DimensionsValue>> dimensionsValuesList =
+ Arrays.asList(DV_PAIR_A, DV_PAIR_MALFORMED);
+
+ assertThrows(
+ StatsConversionException.class,
+ () -> mConverter.convert(
+ atomsList,
+ DIM_FIELDS_IDS,
+ dimensionsValuesList,
+ HASH_STR_MAP));
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
index 39fb772..bf82bda 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/ProcessMemoryStateConverterTest.java
@@ -24,6 +24,7 @@
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.RSS_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.SWAP_IN_BYTES_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.ProcessMemoryState.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -117,24 +118,35 @@
dimensionsValuesList, HASH_STR_MAP);
assertThat(bundle.size()).isEqualTo(8);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
.containsExactly("process.name.1", "process.name.2").inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(OOM_ADJ_SCORE_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ OOM_ADJ_SCORE_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(100, 200).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(PAGE_FAULT_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(59L, 99L).inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PAGE_MAJOR_FAULT_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(34L, 55L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ RSS_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(1234L, 2345L).inOrder();
assertThat(bundle.getLongArray(
- accessorMap.get(CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ CACHE_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(234L, 345L).inOrder();
- assertThat(bundle.getLongArray(accessorMap.get(SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
+ assertThat(bundle.getLongArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ SWAP_IN_BYTES_FIELD_NUMBER).getFieldName()))
.asList().containsExactly(111L, 222L).inOrder();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
index f0dbdd2..c3a4f68 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/publisher/statsconverters/WtfOccurredConverterTest.java
@@ -20,6 +20,7 @@
import static com.android.car.telemetry.AtomsProto.WTFOccurred.PROCESS_NAME_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.WTFOccurred.TAG_FIELD_NUMBER;
import static com.android.car.telemetry.AtomsProto.WTFOccurred.UID_FIELD_NUMBER;
+import static com.android.car.telemetry.publisher.Constants.STATS_BUNDLE_KEY_PREFIX;
import static com.google.common.truth.Truth.assertThat;
@@ -76,15 +77,20 @@
PersistableBundle bundle = mConverter.convert(atomsList, null, null, null);
assertThat(bundle.size()).isEqualTo(4);
- assertThat(bundle.getIntArray(accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
- .asList().containsExactly(1000, 2000).inOrder();
- assertThat(Arrays.asList(
- bundle.getStringArray(accessorMap.get(PROCESS_NAME_FIELD_NUMBER).getFieldName())))
- .containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
- assertThat(bundle.getStringArray(accessorMap.get(TAG_FIELD_NUMBER).getFieldName()))
- .asList().containsExactly("tag1", "tag2").inOrder();
- assertThat(bundle.getIntArray(accessorMap.get(ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
- .asList().containsExactly(1, 2).inOrder(); // DATA_APP=1, SYSTEM_APP=2
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(UID_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(1000, 2000).inOrder();
+ assertThat(Arrays.asList(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ PROCESS_NAME_FIELD_NUMBER).getFieldName())))
+ .containsExactly(PACKAGE_NAME_1, PACKAGE_NAME_2).inOrder();
+ assertThat(bundle.getStringArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(TAG_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly("tag1", "tag2").inOrder();
+ assertThat(bundle.getIntArray(
+ STATS_BUNDLE_KEY_PREFIX + accessorMap.get(
+ ERROR_SOURCE_FIELD_NUMBER).getFieldName()))
+ .asList().containsExactly(1, 2).inOrder(); // DATA_APP=1, SYSTEM_APP=2
}
@Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
index da5917c..d1cc98c 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/sessioncontroller/SessionAnnotationUnitTest.java
@@ -20,6 +20,8 @@
import android.os.PersistableBundle;
+import com.android.car.telemetry.publisher.Constants;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@@ -42,17 +44,17 @@
sAnnotation.addAnnotationsToBundle(data);
- assertThat(data.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(
+ assertThat(data.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_ID)).isEqualTo(
SESSION_ID);
- assertThat(data.getInt(SessionAnnotation.ANNOTATION_BUNDLE_KEY_SESSION_STATE)).isEqualTo(
+ assertThat(data.getInt(Constants.ANNOTATION_BUNDLE_KEY_SESSION_STATE)).isEqualTo(
SESSION_STATE);
assertThat(data.getLong(
- SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS)).isEqualTo(
+ Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_SINCE_BOOT_MILLIS)).isEqualTo(
CREATED_AT_SINCE_BOOT_MILLIS);
assertThat(
- data.getLong(SessionAnnotation.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS)).isEqualTo(
+ data.getLong(Constants.ANNOTATION_BUNDLE_KEY_CREATED_AT_MILLIS)).isEqualTo(
CREATED_AT_MILLIS);
- assertThat(data.getString(SessionAnnotation.ANNOTATION_BUNDLE_KEY_BOOT_REASON)).isEqualTo(
+ assertThat(data.getString(Constants.ANNOTATION_BUNDLE_KEY_BOOT_REASON)).isEqualTo(
BOOT_REASON);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
index dca7764..34dc354 100644
--- a/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/CarWatchdogServiceUnitTest.java
@@ -509,6 +509,34 @@
}
@Test
+ public void testPowerCycleStateChangesDuringSuspend() throws Exception {
+ setCarPowerState(CarPowerManager.STATE_SUSPEND_ENTER);
+ setCarPowerState(CarPowerManager.STATE_SUSPEND_EXIT);
+ setCarPowerState(CarPowerManager.STATE_ON);
+
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER, MISSING_ARG_VALUE);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_SUSPEND_EXIT, MISSING_ARG_VALUE);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_RESUME, MISSING_ARG_VALUE);
+ }
+
+ @Test
+ public void testPowerCycleStateChangesDuringHibernation() throws Exception {
+ setCarPowerState(CarPowerManager.STATE_HIBERNATION_ENTER);
+ setCarPowerState(CarPowerManager.STATE_HIBERNATION_EXIT);
+ setCarPowerState(CarPowerManager.STATE_ON);
+
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER, MISSING_ARG_VALUE);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_SUSPEND_EXIT, MISSING_ARG_VALUE);
+ verify(mMockCarWatchdogDaemon).notifySystemStateChange(StateType.POWER_CYCLE,
+ PowerCycle.POWER_CYCLE_RESUME, MISSING_ARG_VALUE);
+ }
+
+ @Test
public void testDeviceRebootBroadcast() throws Exception {
mBroadcastReceiver.onReceive(mMockContext,
new Intent().setAction(Intent.ACTION_REBOOT)
@@ -4537,11 +4565,7 @@
int userId = userIds[i];
UserHandle userHandle = UserHandle.of(userId);
- mBroadcastReceiver
- .onReceive(mMockContext, new Intent(ACTION_RESOURCE_OVERUSE_DISABLE_APP)
- .putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
- .putExtra(Intent.EXTRA_USER, userHandle)
- .putExtra(INTENT_EXTRA_NOTIFICATION_ID, RESOURCE_OVERUSE_NOTIFICATION_BASE_ID));
+ mCarWatchdogService.performResourceOveruseKill(packageName, userId);
verify(mSpiedPackageManager, atLeastOnce())
.getApplicationEnabledSetting(packageName, userId);