Merge changes from topic "Mute on audio disable" into sc-dev
* changes:
Restricting muting on audio disable
Swap to CarAudioService#setIsAudioEnabled
Add CarVolumeGroup#hasCrticialAudioContexts
diff --git a/car-lib/src/android/car/admin/ICarDevicePolicyService.aidl b/car-lib/src/android/car/admin/ICarDevicePolicyService.aidl
index 3d9bec1..88b42b1 100644
--- a/car-lib/src/android/car/admin/ICarDevicePolicyService.aidl
+++ b/car-lib/src/android/car/admin/ICarDevicePolicyService.aidl
@@ -16,12 +16,16 @@
package android.car.admin;
-import android.car.user.UserRemovalResult;
import android.car.user.UserCreationResult;
+import android.car.user.UserRemovalResult;
+import android.car.user.UserStartResult;
+import android.car.user.UserStopResult;
import com.android.internal.infra.AndroidFuture;
/** @hide */
interface ICarDevicePolicyService {
void removeUser(int userId, in AndroidFuture<UserRemovalResult> receiver);
void createUser(String name, int flags, in AndroidFuture<UserCreationResult> receiver);
+ void startUserInBackground(int userId, in AndroidFuture<UserStartResult> receiver);
+ void stopUser(int userId, in AndroidFuture<UserStopResult> receiver);
}
diff --git a/car-lib/src/android/car/cluster/ClusterState.aidl b/car-lib/src/android/car/cluster/ClusterState.aidl
index 1a9e4f1..a41656c 100644
--- a/car-lib/src/android/car/cluster/ClusterState.aidl
+++ b/car-lib/src/android/car/cluster/ClusterState.aidl
@@ -17,12 +17,12 @@
package android.car.cluster;
import android.graphics.Insets;
+import android.graphics.Rect;
/** @hide */
parcelable ClusterState {
boolean on;
- int width;
- int height;
+ Rect bounds;
Insets insets;
int uiType;
}
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index f73201e..bd47263 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -496,17 +496,45 @@
/**
* Returns value of a bool property
+ *
* <p> This method may take couple seconds to complete, so it needs to be called from an
* non-main thread.
*
+ * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} equal
+ * or later than {@link Build.VERSION_CODES#R} will receive the following exceptions when
+ * request is failed.
+ * <ul>
+ * <li>{@link CarInternalErrorException}
+ * <li>{@link PropertyAccessDeniedSecurityException}
+ * <li>{@link PropertyNotAvailableAndRetryException}
+ * <li>{@link PropertyNotAvailableException}
+ * <li>{@link IllegalArgumentException}
+ * </ul>
+ * <p> Clients that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion}
+ * earlier than {@link Build.VERSION_CODES#R} will receive the following exceptions if the call
+ * fails.
+ * <ul>
+ * <li>{@link IllegalStateException} when there is an error detected in cars.
+ * <li>{@link IllegalArgumentException} when the property in the areaId is not supplied.
+ * </ul>
+ *
* @param prop Property ID to get
* @param area Area of the property to get
- * @return value of a bool property.
+ *
+ * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+ * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+ * property.
+ * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+ * not available and likely that retrying will be successful.
+ * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+ * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+ *
+ * @return value of a bool property, {@code false} if can not get value from cars.
*/
public boolean getBooleanProperty(int prop, int area) {
checkSupportedProperty(prop);
CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
- return carProp != null ? carProp.getValue() : false;
+ return handleNullAndPropertyStatus(carProp, area, false);
}
/**
@@ -515,43 +543,82 @@
* <p> This method may take couple seconds to complete, so it needs to be called from an
* non-main thread.
*
+ * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+ *
* @param prop Property ID to get
* @param area Area of the property to get
+ *
+ * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+ * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+ * property.
+ * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+ * not available and likely that retrying will be successful.
+ * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+ * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+ *
+ * @return value of a float property, 0 if can not get value from the cars.
*/
public float getFloatProperty(int prop, int area) {
checkSupportedProperty(prop);
CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
- return carProp != null ? carProp.getValue() : 0f;
+ return handleNullAndPropertyStatus(carProp, area, 0f);
}
/**
- * Returns value of a integer property
+ * Returns value of an integer property
*
* <p> This method may take couple seconds to complete, so it needs to be called form an
* non-main thread.
+ *
+ * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+ *
* @param prop Property ID to get
* @param area Zone of the property to get
+ *
+ * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+ * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+ * property.
+ * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+ * not available and likely that retrying will be successful.
+ * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+ * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+ *
+ * @return value of an integer property, 0 if can not get the value from cars.
*/
public int getIntProperty(int prop, int area) {
checkSupportedProperty(prop);
CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
- return carProp != null ? carProp.getValue() : 0;
+ return handleNullAndPropertyStatus(carProp, area, 0);
}
/**
- * Returns value of a integer array property
+ * Returns value of an integer array property
*
* <p> This method may take couple seconds to complete, so it needs to be called from an
* non-main thread.
*
+ * <p> This method has the same exception behavior as {@link #getBooleanProperty(int, int)}.
+ *
* @param prop Property ID to get
* @param area Zone of the property to get
+ *
+ * @throws {@link CarInternalErrorException} when there is an error detected in cars.
+ * @throws {@link PropertyAccessDeniedSecurityException} when cars denied the access of the
+ * property.
+ * @throws {@link PropertyNotAvailableAndRetryException} when the property is temporarily
+ * not available and likely that retrying will be successful.
+ * @throws {@link PropertyNotAvailableException} when the property is temporarily not available.
+ * @throws {@link IllegalArgumentException} when the property in the areaId is not supplied.
+ *
+ * @return value of an integer array property, an empty integer array if can not get the value
+ * from cars.
*/
@NonNull
public int[] getIntArrayProperty(int prop, int area) {
checkSupportedProperty(prop);
CarPropertyValue<Integer[]> carProp = getProperty(Integer[].class, prop, area);
- return carProp != null ? toIntArray(carProp.getValue()) : new int[0];
+ Integer[] res = handleNullAndPropertyStatus(carProp, area, new Integer[0]);
+ return toIntArray(res);
}
private static int[] toIntArray(Integer[] input) {
@@ -563,6 +630,30 @@
return arr;
}
+ private <T> T handleNullAndPropertyStatus(CarPropertyValue<T> propertyValue, int areaId,
+ T defaultValue) {
+
+ if (propertyValue == null) {
+ return defaultValue;
+ }
+
+ // Keeps the same behavior as android R.
+ if (mAppTargetSdk < Build.VERSION_CODES.S) {
+ return propertyValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE
+ ? propertyValue.getValue() : defaultValue;
+ }
+
+ // throws new exceptions in android S.
+ switch (propertyValue.getStatus()) {
+ case CarPropertyValue.STATUS_ERROR:
+ throw new CarInternalErrorException(propertyValue.getPropertyId(), areaId);
+ case CarPropertyValue.STATUS_UNAVAILABLE:
+ throw new PropertyNotAvailableException(propertyValue.getPropertyId(), areaId);
+ default:
+ return propertyValue.getValue();
+ }
+ }
+
/**
* Return CarPropertyValue
*
diff --git a/car-lib/src/android/car/user/UserStartResult.aidl b/car-lib/src/android/car/user/UserStartResult.aidl
new file mode 100644
index 0000000..d5333ec
--- /dev/null
+++ b/car-lib/src/android/car/user/UserStartResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.car.user;
+
+parcelable UserStartResult;
diff --git a/car-lib/src/android/car/user/UserStartResult.java b/car-lib/src/android/car/user/UserStartResult.java
new file mode 100644
index 0000000..d1a5d32
--- /dev/null
+++ b/car-lib/src/android/car/user/UserStartResult.java
@@ -0,0 +1,242 @@
+/*
+ * 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 android.car.user;
+
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * User start results.
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public final class UserStartResult implements Parcelable, OperationResult {
+
+ /**
+ * When user start is successful.
+ *
+ * @hide
+ */
+ public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+ /**
+ * When user start failed.
+ *
+ * @hide
+ */
+ public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+ /**
+ * When user to start is same as current user.
+ *
+ * @hide
+ */
+ public static final int STATUS_SUCCESSFUL_USER_IS_CURRENT_USER =
+ CommonResults.LAST_COMMON_STATUS + 1;
+
+ /**
+ * When user to start does not exist.
+ *
+ * @hide
+ */
+ public static final int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 2;
+
+ /**
+ * Gets the user start result status.
+ *
+ * @return either {@link UserStartRsult#STATUS_SUCCESSFUL},
+ * {@link UserStartResult#STATUS_SUCCESSFUL_USER_IS_CURRENT_USER},
+ * {@link UserStartResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStartResult#STATUS_USER_DOES_NOT_EXIST}, or
+ */
+ private final @Status int mStatus;
+
+ @Override
+ public boolean isSuccess() {
+ return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_SUCCESSFUL_USER_IS_CURRENT_USER;
+ }
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserStartResult.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @android.annotation.IntDef(prefix = "STATUS_", value = {
+ STATUS_SUCCESSFUL,
+ STATUS_ANDROID_FAILURE,
+ STATUS_SUCCESSFUL_USER_IS_CURRENT_USER,
+ STATUS_USER_DOES_NOT_EXIST
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Status {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String statusToString(@Status int value) {
+ switch (value) {
+ case STATUS_SUCCESSFUL:
+ return "STATUS_SUCCESSFUL";
+ case STATUS_ANDROID_FAILURE:
+ return "STATUS_ANDROID_FAILURE";
+ case STATUS_SUCCESSFUL_USER_IS_CURRENT_USER:
+ return "STATUS_SUCCESSFUL_USER_IS_CURRENT_USER";
+ case STATUS_USER_DOES_NOT_EXIST:
+ return "STATUS_USER_DOES_NOT_EXIST";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /**
+ * Creates a new UserStartResult.
+ *
+ * @param status
+ * Gets the user start result status.
+ *
+ * @return either {@link UserStartRsult#STATUS_SUCCESSFUL},
+ * {@link UserStartResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStartResult#STATUS_SUCCESSFUL_USER_IS_CURRENT_USER},
+ * {@link UserStartResult#STATUS_USER_DOES_NOT_EXIST}, or
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public UserStartResult(
+ @Status int status) {
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_SUCCESSFUL_USER_IS_CURRENT_USER)
+ && !(mStatus == STATUS_USER_DOES_NOT_EXIST)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_SUCCESSFUL_USER_IS_CURRENT_USER(" + STATUS_SUCCESSFUL_USER_IS_CURRENT_USER + "), "
+ + "STATUS_USER_DOES_NOT_EXIST(" + STATUS_USER_DOES_NOT_EXIST + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Gets the user start result status.
+ *
+ * @return either {@link UserStartRsult#STATUS_SUCCESSFUL},
+ * {@link UserStartResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStartResult#STATUS_SUCCESSFUL_USER_IS_CURRENT_USER},
+ * {@link UserStartResult#STATUS_USER_DOES_NOT_EXIST}, or
+ */
+ @DataClass.Generated.Member
+ public @Status int getStatus() {
+ return mStatus;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "UserStartResult { " +
+ "status = " + statusToString(mStatus) +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mStatus);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ UserStartResult(@android.annotation.NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int status = in.readInt();
+
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_SUCCESSFUL_USER_IS_CURRENT_USER)
+ && !(mStatus == STATUS_USER_DOES_NOT_EXIST)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_SUCCESSFUL_USER_IS_CURRENT_USER(" + STATUS_SUCCESSFUL_USER_IS_CURRENT_USER + "), "
+ + "STATUS_USER_DOES_NOT_EXIST(" + STATUS_USER_DOES_NOT_EXIST + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<UserStartResult> CREATOR
+ = new Parcelable.Creator<UserStartResult>() {
+ @Override
+ public UserStartResult[] newArray(int size) {
+ return new UserStartResult[size];
+ }
+
+ @Override
+ public UserStartResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+ return new UserStartResult(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1618957103487L,
+ codegenVersion = "1.0.23",
+ sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserStartResult.java",
+ inputSignatures = "public static final int STATUS_SUCCESSFUL\npublic static final int STATUS_ANDROID_FAILURE\npublic static final int STATUS_SUCCESSFUL_USER_IS_CURRENT_USER\npublic static final int STATUS_USER_DOES_NOT_EXIST\nprivate final @android.car.user.UserStartResult.Status int mStatus\npublic @java.lang.Override boolean isSuccess()\nclass UserStartResult extends java.lang.Object implements [android.os.Parcelable, android.car.user.OperationResult]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/car-lib/src/android/car/user/UserStopResult.aidl b/car-lib/src/android/car/user/UserStopResult.aidl
new file mode 100644
index 0000000..d90eb46
--- /dev/null
+++ b/car-lib/src/android/car/user/UserStopResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.car.user;
+
+parcelable UserStopResult;
\ No newline at end of file
diff --git a/car-lib/src/android/car/user/UserStopResult.java b/car-lib/src/android/car/user/UserStopResult.java
new file mode 100644
index 0000000..5f17220
--- /dev/null
+++ b/car-lib/src/android/car/user/UserStopResult.java
@@ -0,0 +1,262 @@
+/*
+ * 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 android.car.user;
+
+import android.annotation.IntDef;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * User remove result.
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public final class UserStopResult implements Parcelable, OperationResult {
+
+ /**
+ * When user stop is successful.
+ */
+ public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
+
+ /**
+ * When user stop fails.
+ */
+ public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
+
+ /**
+ * When user to stop doesn't exits.
+ */
+ public static final int STATUS_USER_DOES_NOT_EXIST = CommonResults.LAST_COMMON_STATUS + 1;
+
+ /**
+ * When user to stop is the system user.
+ */
+ public static final int STATUS_FAILURE_SYSTEM_USER = CommonResults.LAST_COMMON_STATUS + 2;
+
+ /**
+ * When user to stop is the current user.
+ */
+ public static final int STATUS_FAILURE_CURRENT_USER = CommonResults.LAST_COMMON_STATUS + 3;
+
+ /**
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserStopResult#STATUS_SUCCESSFUL},
+ * {@link UserStopResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStopResult#STATUS_USER_DOES_NOT_EXIST},
+ * {@link UserStopResult#STATUS_FAILURE_SYSTEM_USER}, or
+ * {@link UserStopResult#STATUS_FAILURE_CURRENT_USER}.
+ */
+ private final @Status int mStatus;
+
+ /**
+ * Checks if the {@code status} represents a success status.
+ *
+ * @param status to check
+ * @return true for a success status
+ */
+ public static boolean isSuccess(@Status int status) {
+ return status == STATUS_SUCCESSFUL;
+ }
+
+ @Override
+ public boolean isSuccess() {
+ return isSuccess(mStatus);
+ }
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserStopResult.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @IntDef(prefix = "STATUS_", value = {
+ STATUS_SUCCESSFUL,
+ STATUS_ANDROID_FAILURE,
+ STATUS_USER_DOES_NOT_EXIST,
+ STATUS_FAILURE_SYSTEM_USER,
+ STATUS_FAILURE_CURRENT_USER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Status {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String statusToString(@Status int value) {
+ switch (value) {
+ case STATUS_SUCCESSFUL:
+ return "STATUS_SUCCESSFUL";
+ case STATUS_ANDROID_FAILURE:
+ return "STATUS_ANDROID_FAILURE";
+ case STATUS_USER_DOES_NOT_EXIST:
+ return "STATUS_USER_DOES_NOT_EXIST";
+ case STATUS_FAILURE_SYSTEM_USER:
+ return "STATUS_FAILURE_SYSTEM_USER";
+ case STATUS_FAILURE_CURRENT_USER:
+ return "STATUS_FAILURE_CURRENT_USER";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /**
+ * Creates a new UserStopResult.
+ *
+ * @param status
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserStopResult#STATUS_SUCCESSFUL},
+ * {@link UserStopResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStopResult#STATUS_USER_DOES_NOT_EXIST},
+ * {@link UserStopResult#STATUS_FAILURE_SYSTEM_USER}, or
+ * {@link UserStopResult#STATUS_FAILURE_CURRENT_USER}.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public UserStopResult(
+ @Status int status) {
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_USER_DOES_NOT_EXIST)
+ && !(mStatus == STATUS_FAILURE_SYSTEM_USER)
+ && !(mStatus == STATUS_FAILURE_CURRENT_USER)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_USER_DOES_NOT_EXIST(" + STATUS_USER_DOES_NOT_EXIST + "), "
+ + "STATUS_FAILURE_SYSTEM_USER(" + STATUS_FAILURE_SYSTEM_USER + "), "
+ + "STATUS_FAILURE_CURRENT_USER(" + STATUS_FAILURE_CURRENT_USER + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * Gets the user switch result status.
+ *
+ * @return either {@link UserStopResult#STATUS_SUCCESSFUL},
+ * {@link UserStopResult#STATUS_ANDROID_FAILURE},
+ * {@link UserStopResult#STATUS_USER_DOES_NOT_EXIST},
+ * {@link UserStopResult#STATUS_FAILURE_SYSTEM_USER}, or
+ * {@link UserStopResult#STATUS_FAILURE_CURRENT_USER}.
+ */
+ @DataClass.Generated.Member
+ public @Status int getStatus() {
+ return mStatus;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "UserStopResult { " +
+ "status = " + statusToString(mStatus) +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeInt(mStatus);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ UserStopResult(@android.annotation.NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ int status = in.readInt();
+
+ this.mStatus = status;
+
+ if (!(mStatus == STATUS_SUCCESSFUL)
+ && !(mStatus == STATUS_ANDROID_FAILURE)
+ && !(mStatus == STATUS_USER_DOES_NOT_EXIST)
+ && !(mStatus == STATUS_FAILURE_SYSTEM_USER)
+ && !(mStatus == STATUS_FAILURE_CURRENT_USER)) {
+ throw new java.lang.IllegalArgumentException(
+ "status was " + mStatus + " but must be one of: "
+ + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
+ + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
+ + "STATUS_USER_DOES_NOT_EXIST(" + STATUS_USER_DOES_NOT_EXIST + "), "
+ + "STATUS_FAILURE_SYSTEM_USER(" + STATUS_FAILURE_SYSTEM_USER + "), "
+ + "STATUS_FAILURE_CURRENT_USER(" + STATUS_FAILURE_CURRENT_USER + ")");
+ }
+
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @android.annotation.NonNull Parcelable.Creator<UserStopResult> CREATOR
+ = new Parcelable.Creator<UserStopResult>() {
+ @Override
+ public UserStopResult[] newArray(int size) {
+ return new UserStopResult[size];
+ }
+
+ @Override
+ public UserStopResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
+ return new UserStopResult(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1619209981496L,
+ codegenVersion = "1.0.23",
+ sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserStopResult.java",
+ inputSignatures = "public static final int STATUS_SUCCESSFUL\npublic static final int STATUS_ANDROID_FAILURE\npublic static final int STATUS_USER_DOES_NOT_EXIST\npublic static final int STATUS_FAILURE_SYSTEM_USER\npublic static final int STATUS_FAILURE_CURRENT_USER\nprivate final @android.car.user.UserStopResult.Status int mStatus\npublic static boolean isSuccess(int)\npublic @java.lang.Override boolean isSuccess()\nclass UserStopResult extends java.lang.Object implements [android.os.Parcelable, android.car.user.OperationResult]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
index 588ac13..05cba98 100644
--- a/car-lib/src/android/car/watchdog/CarWatchdogManager.java
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -694,6 +694,7 @@
* @param resourceOveruseFlag Flag to indicate the types of resource overuse configurations to
* return.
*
+ * @throws IllegalStateException if the system is in an invalid state.
* @hide
*/
@SystemApi
diff --git a/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
index aaf12a7..9430723 100644
--- a/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
+++ b/car-test-lib/src/android/car/test/mocks/JavaMockitoHelper.java
@@ -89,8 +89,7 @@
* {@value #ASYNC_TIMEOUT_MS} ms.
*/
@NonNull
- public static <T> T getResult(@NonNull Future<T> future)
- throws InterruptedException, ExecutionException {
+ public static <T> T getResult(@NonNull Future<T> future) {
return getResult(future, ASYNC_TIMEOUT_MS);
}
diff --git a/car-test-lib/src/android/car/testapi/FakeCar.java b/car-test-lib/src/android/car/testapi/FakeCar.java
index 4a3a98a..0356774 100644
--- a/car-test-lib/src/android/car/testapi/FakeCar.java
+++ b/car-test-lib/src/android/car/testapi/FakeCar.java
@@ -24,7 +24,6 @@
import android.car.diagnostic.ICarDiagnostic;
import android.car.drivingstate.ICarDrivingState;
import android.car.hardware.power.ICarPower;
-import android.car.media.ICarAudio;
import android.car.storagemonitoring.ICarStorageMonitoring;
import android.content.Context;
import android.os.IBinder;
@@ -129,7 +128,6 @@
}
private static class FakeCarService extends ICar.Stub {
- @Mock ICarAudio.Stub mCarAudio;
@Mock ICarPackageManager.Stub mCarPackageManager;
@Mock ICarDiagnostic.Stub mCarDiagnostic;
@Mock ICarPower.Stub mCarPower;
@@ -138,6 +136,7 @@
@Mock ICarStorageMonitoring.Stub mCarStorageMonitoring;
@Mock ICarDrivingState.Stub mCarDrivingState;
+ private final FakeCarAudioService mCarAudio;
private final FakeAppFocusService mAppFocus;
private final FakeCarPropertyService mCarProperty;
private final FakeCarProjectionService mCarProjection;
@@ -146,6 +145,7 @@
FakeCarService(Context context) {
MockitoAnnotations.initMocks(this);
+ mCarAudio = new FakeCarAudioService();
mAppFocus = new FakeAppFocusService(context);
mCarProperty = new FakeCarPropertyService();
mCarProjection = new FakeCarProjectionService(context);
diff --git a/car-test-lib/src/android/car/testapi/FakeCarAudioService.java b/car-test-lib/src/android/car/testapi/FakeCarAudioService.java
new file mode 100644
index 0000000..7b0bb09
--- /dev/null
+++ b/car-test-lib/src/android/car/testapi/FakeCarAudioService.java
@@ -0,0 +1,146 @@
+/*
+ * 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 android.car.testapi;
+
+import android.car.media.CarAudioPatchHandle;
+import android.car.media.ICarAudio;
+import android.media.AudioDeviceAttributes;
+import android.os.IBinder;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Fake service that is used by {@link FakeCar} to provide an implementation of {@link ICarAudio}.
+ * The reason we couldn't use a mock version of this service is that {@link AudioDeviceAttributes}
+ * is annotated with @hide, and Mockito fails to create a mock instance.
+ */
+final class FakeCarAudioService extends ICarAudio.Stub {
+ @Override
+ public boolean isAudioFeatureEnabled(int feature) {
+ return false;
+ }
+
+ @Override
+ public void setGroupVolume(int zoneId, int groupId, int index, int flags) {
+ }
+
+ @Override
+ public int getGroupMaxVolume(int zoneId, int groupId) {
+ return 0;
+ }
+
+ @Override
+ public int getGroupMinVolume(int zoneId, int groupId) {
+ return 0;
+ }
+
+ @Override
+ public int getGroupVolume(int zoneId, int groupId) {
+ return 0;
+ }
+
+ @Override
+ public void setFadeTowardFront(float value) {
+ }
+
+ @Override
+ public void setBalanceTowardRight(float value) {
+ }
+
+ @Override
+ public String[] getExternalSources() {
+ return new String[] {};
+ }
+
+ @Override
+ public CarAudioPatchHandle createAudioPatch(String sourceAddress, int usage,
+ int gainInMillibels) {
+ return null;
+ }
+
+ @Override
+ public void releaseAudioPatch(CarAudioPatchHandle patch) {
+ }
+
+ @Override
+ public int getVolumeGroupCount(int zoneId) {
+ return 0;
+ }
+
+ @Override
+ public int getVolumeGroupIdForUsage(int zoneId, int usage) {
+ return 0;
+ }
+
+ @Override
+ public int[] getUsagesForVolumeGroupId(int zoneId, int groupId) {
+ return new int[] {};
+ }
+
+ @Override
+ public int[] getAudioZoneIds() {
+ return new int[] {};
+ }
+
+ @Override
+ public int getZoneIdForUid(int uid) {
+ return 0;
+ }
+
+ @Override
+ public boolean setZoneIdForUid(int zoneId, int uid) {
+ return false;
+ }
+
+ @Override
+ public boolean clearZoneIdForUid(int uid) {
+ return false;
+ }
+
+ @Override
+ public boolean isVolumeGroupMuted(int zoneId, int groupId) {
+ return false;
+ }
+
+ @Override
+ public void setVolumeGroupMute(int zoneId, int groupId, boolean mute, int flags) {
+ }
+
+ @Override
+ public String getOutputDeviceAddressForUsage(int zoneId, int usage) {
+ return "";
+ }
+
+ @Override
+ public List<AudioDeviceAttributes> getInputDevicesForZoneId(int zoneId) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean isPlaybackOnVolumeGroupActive(int volumeGroupId, int audioZoneId) {
+ return false;
+ }
+
+ @Override
+ public void registerVolumeCallback(IBinder binder) {
+ }
+
+ @Override
+ public void unregisterVolumeCallback(IBinder binder) {
+ }
+}
diff --git a/car_product/build/car_base.mk b/car_product/build/car_base.mk
index 41408eb..2f9b344 100644
--- a/car_product/build/car_base.mk
+++ b/car_product/build/car_base.mk
@@ -65,6 +65,9 @@
# EVS service
include packages/services/Car/cpp/evs/manager/evsmanager.mk
+# Automotive Telemetry services
+include packages/services/Car/cpp/telemetry/products/telemetry.mk
+
# EVS manager overrides cameraserver on automotive implementations so
# we need to configure Camera API to not connect to it
PRODUCT_PROPERTY_OVERRIDES += config.disable_cameraservice=true
diff --git a/cpp/evs/OWNERS b/cpp/evs/OWNERS
index cc4938d..1830653 100644
--- a/cpp/evs/OWNERS
+++ b/cpp/evs/OWNERS
@@ -1,4 +1,5 @@
# Project owners
changyeon@google.com
+garysungang@google.com
haoxiangl@google.com
-swan@google.com
+
diff --git a/cpp/evs/apps/default/config.json b/cpp/evs/apps/default/config.json
index 16148a7..dc2771c 100644
--- a/cpp/evs/apps/default/config.json
+++ b/cpp/evs/apps/default/config.json
@@ -8,7 +8,7 @@
},
"displays" : [
{
- "displayPort" : 136,
+ "displayPort" : 129,
"frontRange" : 100,
"rearRange" : 100
},
diff --git a/cpp/security/OWNERS b/cpp/security/OWNERS
new file mode 100644
index 0000000..45f51c0
--- /dev/null
+++ b/cpp/security/OWNERS
@@ -0,0 +1,2 @@
+dbenisch@google.com
+skeys@google.com
diff --git a/cpp/surround_view/app/Android.bp b/cpp/surround_view/app/Android.bp
index 5145c5e..76753d3 100644
--- a/cpp/surround_view/app/Android.bp
+++ b/cpp/surround_view/app/Android.bp
@@ -23,6 +23,7 @@
name: "sv_app",
srcs: [
+ "SurroundViewAppCommon.cpp",
"SurroundViewServiceCallback.cpp",
"shader.cpp",
"sv_app.cpp",
diff --git a/cpp/surround_view/app/SurroundViewAppCommon.cpp b/cpp/surround_view/app/SurroundViewAppCommon.cpp
new file mode 100644
index 0000000..b1a2792
--- /dev/null
+++ b/cpp/surround_view/app/SurroundViewAppCommon.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include "SurroundViewAppCommon.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace app {
+
+bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay) {
+ LOG(INFO) << "Run 2d Surround View demo";
+
+ // Call HIDL API "start2dSession"
+ sp<ISurroundView2dSession> surroundView2dSession;
+
+ SvResult svResult;
+ pSurroundViewService->start2dSession(
+ [&surroundView2dSession, &svResult](const sp<ISurroundView2dSession>& session,
+ SvResult result) {
+ surroundView2dSession = session;
+ svResult = result;
+ });
+
+ if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
+ LOG(ERROR) << "Failed to start2dSession";
+ return false;
+ } else {
+ LOG(INFO) << "start2dSession succeeded";
+ }
+
+ sp<SurroundViewServiceCallback> sv2dCallback =
+ new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
+
+ // Start 2d stream with callback with default quality and resolution.
+ // The quality is defaulted to be HIGH_QUALITY, and the default resolution
+ // is set in the sv config file.
+ if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
+ LOG(ERROR) << "Failed to start 2d stream";
+ return false;
+ }
+
+ const int kTotalViewingTimeSecs = 10;
+
+ // Let the SV algorithm run for HIGH_QUALITY until the wait time finishes
+ std::this_thread::sleep_for(std::chrono::seconds(kTotalViewingTimeSecs));
+
+ // Switch to low quality and lower resolution
+ Sv2dConfig config = {.width = kLowResolutionWidth, .blending = SvQuality::LOW};
+ if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
+ LOG(ERROR) << "Failed to set2dConfig";
+ return false;
+ }
+
+ // Let the SV algorithm run for LOW_QUALITY until the wait time finishes
+ std::this_thread::sleep_for(std::chrono::seconds(kTotalViewingTimeSecs));
+
+ // TODO(b/150412555): wait for the last frame
+ // Stop the 2d stream and session
+ surroundView2dSession->stopStream();
+
+ pSurroundViewService->stop2dSession(surroundView2dSession);
+ surroundView2dSession = nullptr;
+
+ LOG(INFO) << "SV 2D session finished.";
+
+ return true;
+};
+
+// Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
+bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId, uint32_t poseIndex,
+ float hfov) {
+ const View3d view3d = {
+ .viewId = viewId,
+ .pose =
+ {
+ .rotation = {.x = kPoseRot[poseIndex][0],
+ .y = kPoseRot[poseIndex][1],
+ .z = kPoseRot[poseIndex][2],
+ .w = kPoseRot[poseIndex][3]},
+ .translation = {.x = kPoseTrans[poseIndex][0],
+ .y = kPoseTrans[poseIndex][1],
+ .z = kPoseTrans[poseIndex][2]},
+ },
+ .horizontalFov = hfov,
+ };
+
+ const std::vector<View3d> views = {view3d};
+ if (surroundView3dSession->setViews(views) != SvResult::OK) {
+ return false;
+ }
+ return true;
+}
+
+bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay) {
+ LOG(INFO) << "Run 3d Surround View demo";
+
+ // Call HIDL API "start3dSession"
+ sp<ISurroundView3dSession> surroundView3dSession;
+
+ SvResult svResult;
+ pSurroundViewService->start3dSession(
+ [&surroundView3dSession, &svResult](const sp<ISurroundView3dSession>& session,
+ SvResult result) {
+ surroundView3dSession = session;
+ svResult = result;
+ });
+
+ if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
+ LOG(ERROR) << "Failed to start3dSession";
+ return false;
+ } else {
+ LOG(INFO) << "start3dSession succeeded";
+ }
+
+ sp<SurroundViewServiceCallback> sv3dCallback =
+ new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
+
+ // A view must be set before the 3d stream is started.
+ if (!setView(surroundView3dSession, /*viewId=*/0, /*poseIndex=*/0, kHorizontalFov)) {
+ LOG(ERROR) << "Failed to setView of pose index :" << 0;
+ return false;
+ }
+
+ // Start 3d stream with callback with default quality and resolution.
+ // The quality is defaulted to be HIGH_QUALITY, and the default resolution
+ // is set in the sv config file.
+ if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
+ LOG(ERROR) << "Failed to start 3d stream";
+ return false;
+ }
+
+ // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
+ const int kTotalViewingTimeSecs = 10;
+ const std::chrono::milliseconds perPoseSleepTimeMs(kTotalViewingTimeSecs * 1000 / kPoseCount);
+ // Iterate through the pre-set views.
+ for (uint32_t i = 0; i < kPoseCount; i++) {
+ if (!setView(surroundView3dSession, /*viewId=*/i, /*poseIndex=*/i, kHorizontalFov)) {
+ LOG(WARNING) << "Failed to setView of pose index :" << i;
+ }
+ std::this_thread::sleep_for(perPoseSleepTimeMs);
+ }
+
+ // Switch to low quality and lower resolution
+ Sv3dConfig config = {.width = kLowResolutionWidth,
+ .height = kLowResolutionHeight,
+ .carDetails = SvQuality::LOW};
+
+ if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
+ LOG(ERROR) << "Failed to set3dConfig";
+ return false;
+ }
+
+ // Let the SV algorithm run for 10 seconds for LOW_QUALITY
+ for (uint32_t i = 0; i < kPoseCount; i++) {
+ if (!setView(surroundView3dSession, i + kPoseCount, i, kHorizontalFov)) {
+ LOG(WARNING) << "Failed to setView of pose index :" << i;
+ }
+ std::this_thread::sleep_for(perPoseSleepTimeMs);
+ }
+
+ // TODO(b/150412555): wait for the last frame
+ // Stop the 3d stream and session
+ surroundView3dSession->stopStream();
+
+ pSurroundViewService->stop3dSession(surroundView3dSession);
+ surroundView3dSession = nullptr;
+
+ LOG(DEBUG) << "SV 3D session finished.";
+
+ return true;
+};
+} // namespace app
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/cpp/surround_view/app/SurroundViewAppCommon.h b/cpp/surround_view/app/SurroundViewAppCommon.h
new file mode 100644
index 0000000..04e59fa
--- /dev/null
+++ b/cpp/surround_view/app/SurroundViewAppCommon.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2020 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.
+ */
+#pragma once
+
+#include "SurroundViewServiceCallback.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+
+#include <stdio.h>
+
+#include <thread>
+
+using namespace android::hardware::automotive::sv::V1_0;
+using namespace android::hardware::automotive::evs::V1_1;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace app {
+
+const int kLowResolutionWidth = 120;
+const int kLowResolutionHeight = 90;
+
+enum DemoMode {
+ UNKNOWN,
+ DEMO_2D,
+ DEMO_3D,
+};
+
+const float kHorizontalFov = 90;
+
+// Number of views to generate.
+const uint32_t kPoseCount = 16;
+
+// Set of pose rotations expressed in quaternions.
+// Views are generated about a circle at a height about the car, point towards the center.
+const float kPoseRot[kPoseCount][4] = {{-0.251292, -0.251292, -0.660948, 0.660948},
+ {0.197439, 0.295488, 0.777193, -0.519304},
+ {0.135998, 0.328329, 0.86357, -0.357702},
+ {0.0693313, 0.348552, 0.916761, -0.182355},
+ {-7.76709e-09, 0.355381, 0.934722, 2.0429e-08},
+ {-0.0693313, 0.348552, 0.916761, 0.182355},
+ {-0.135998, 0.328329, 0.86357, 0.357702},
+ {-0.197439, 0.295488, 0.777193, 0.519304},
+ {-0.251292, 0.251292, 0.660948, 0.660948},
+ {-0.295488, 0.197439, 0.519304, 0.777193},
+ {-0.328329, 0.135998, 0.357702, 0.86357},
+ {-0.348552, 0.0693313, 0.182355, 0.916761},
+ {-0.355381, -2.11894e-09, -5.57322e-09, 0.934722},
+ {-0.348552, -0.0693313, -0.182355, 0.916761},
+ {-0.328329, -0.135998, -0.357702, 0.86357},
+ {-0.295488, -0.197439, -0.519304, 0.777193}};
+
+// Set of pose translations i.e. positions of the views.
+// Views are generated about a circle at a height about the car, point towards the center.
+const float kPoseTrans[kPoseCount][4] = {{4, 0, 2.5},
+ {3.69552, 1.53073, 2.5},
+ {2.82843, 2.82843, 2.5},
+ {1.53073, 3.69552, 2.5},
+ {-1.74846e-07, 4, 2.5},
+ {-1.53073, 3.69552, 2.5},
+ {-2.82843, 2.82843, 2.5},
+ {-3.69552, 1.53073, 2.5},
+ {-4, -3.49691e-07, 2.5},
+ {-3.69552, -1.53073, 2.5},
+ {-2.82843, -2.82843, 2.5},
+ {-1.53073, -3.69552, 2.5},
+ {4.76995e-08, -4, 2.5},
+ {1.53073, -3.69552, 2.5},
+ {2.82843, -2.82843, 2.5},
+ {3.69552, -1.53073, 2.5}};
+
+bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay);
+
+bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService, sp<IEvsDisplay> pDisplay);
+
+// Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
+bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId, uint32_t poseIndex,
+ float hfov);
+
+} // namespace app
+} // namespace sv
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/cpp/surround_view/app/SurroundViewServiceCallback.cpp b/cpp/surround_view/app/SurroundViewServiceCallback.cpp
index 12dba98..a3ce519 100644
--- a/cpp/surround_view/app/SurroundViewServiceCallback.cpp
+++ b/cpp/surround_view/app/SurroundViewServiceCallback.cpp
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include "SurroundViewServiceCallback.h"
#include <android-base/logging.h>
@@ -441,15 +440,6 @@
LOG(INFO) << "Successfully attached render target";
}
- // Call HIDL API "doneWithFrames" to return the ownership
- // back to SV service
- if (mSession == nullptr) {
- LOG(ERROR) << "SurroundViewSession in callback is invalid";
- return {};
- } else {
- mSession->doneWithFrames(svFramesDesc);
- }
-
// Render frame to EVS display
LOG(INFO) << "Rendering to display buffer";
sp<GraphicBuffer> graphicBuffer =
diff --git a/cpp/surround_view/app/SurroundViewServiceCallback.h b/cpp/surround_view/app/SurroundViewServiceCallback.h
index b2ab831..467c69a 100644
--- a/cpp/surround_view/app/SurroundViewServiceCallback.h
+++ b/cpp/surround_view/app/SurroundViewServiceCallback.h
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
+
#include <stdio.h>
#include <utils/StrongPointer.h>
diff --git a/cpp/surround_view/app/sv_app.cpp b/cpp/surround_view/app/sv_app.cpp
index 43369c2..d07671d 100644
--- a/cpp/surround_view/app/sv_app.cpp
+++ b/cpp/surround_view/app/sv_app.cpp
@@ -14,17 +14,7 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
-#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
-#include <hidl/HidlTransportSupport.h>
-#include <stdio.h>
-#include <utils/StrongPointer.h>
-#include <utils/Log.h>
-#include <thread>
-
+#include "SurroundViewAppCommon.h"
#include "SurroundViewServiceCallback.h"
// libhidl:
@@ -40,220 +30,7 @@
using namespace android::hardware::automotive::sv::V1_0;
using namespace android::hardware::automotive::evs::V1_1;
-
-const int kLowResolutionWidth = 120;
-const int kLowResolutionHeight = 90;
-
-enum DemoMode {
- UNKNOWN,
- DEMO_2D,
- DEMO_3D,
-};
-
-const float kHorizontalFov = 90;
-
-// Number of views to generate.
-const uint32_t kPoseCount = 16;
-
-// Set of pose rotations expressed in quaternions.
-// Views are generated about a circle at a height about the car, point towards the center.
-const float kPoseRot[kPoseCount][4] = {
- {-0.251292, -0.251292, -0.660948, 0.660948},
- {0.197439, 0.295488, 0.777193, -0.519304},
- {0.135998, 0.328329, 0.86357, -0.357702},
- {0.0693313, 0.348552, 0.916761, -0.182355},
- {-7.76709e-09, 0.355381, 0.934722, 2.0429e-08},
- {-0.0693313, 0.348552, 0.916761, 0.182355},
- {-0.135998, 0.328329, 0.86357, 0.357702},
- {-0.197439, 0.295488, 0.777193, 0.519304},
- {-0.251292, 0.251292, 0.660948, 0.660948},
- {-0.295488, 0.197439, 0.519304, 0.777193},
- {-0.328329, 0.135998, 0.357702, 0.86357},
- {-0.348552, 0.0693313, 0.182355, 0.916761},
- {-0.355381, -2.11894e-09, -5.57322e-09, 0.934722},
- {-0.348552, -0.0693313, -0.182355, 0.916761},
- {-0.328329, -0.135998, -0.357702, 0.86357},
- {-0.295488, -0.197439, -0.519304, 0.777193}
-};
-
-// Set of pose translations i.e. positions of the views.
-// Views are generated about a circle at a height about the car, point towards the center.
-const float kPoseTrans[kPoseCount][4] = {
- {4, 0, 2.5},
- {3.69552, 1.53073, 2.5},
- {2.82843, 2.82843, 2.5},
- {1.53073, 3.69552, 2.5},
- {-1.74846e-07, 4, 2.5},
- {-1.53073, 3.69552, 2.5},
- {-2.82843, 2.82843, 2.5},
- {-3.69552, 1.53073, 2.5},
- {-4, -3.49691e-07, 2.5},
- {-3.69552, -1.53073, 2.5},
- {-2.82843, -2.82843, 2.5},
- {-1.53073, -3.69552, 2.5},
- {4.76995e-08, -4, 2.5},
- {1.53073, -3.69552, 2.5},
- {2.82843, -2.82843, 2.5},
- {3.69552, -1.53073, 2.5}
-};
-
-bool run2dSurroundView(sp<ISurroundViewService> pSurroundViewService,
- sp<IEvsDisplay> pDisplay) {
- LOG(INFO) << "Run 2d Surround View demo";
-
- // Call HIDL API "start2dSession"
- sp<ISurroundView2dSession> surroundView2dSession;
-
- SvResult svResult;
- pSurroundViewService->start2dSession(
- [&surroundView2dSession, &svResult](
- const sp<ISurroundView2dSession>& session, SvResult result) {
- surroundView2dSession = session;
- svResult = result;
- });
-
- if (surroundView2dSession == nullptr || svResult != SvResult::OK) {
- LOG(ERROR) << "Failed to start2dSession";
- return false;
- } else {
- LOG(INFO) << "start2dSession succeeded";
- }
-
- sp<SurroundViewServiceCallback> sv2dCallback
- = new SurroundViewServiceCallback(pDisplay, surroundView2dSession);
-
- // Start 2d stream with callback
- if (surroundView2dSession->startStream(sv2dCallback) != SvResult::OK) {
- LOG(ERROR) << "Failed to start 2d stream";
- return false;
- }
-
- // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
- std::this_thread::sleep_for(std::chrono::seconds(10));
-
- // Switch to low quality and lower resolution
- Sv2dConfig config;
- config.width = kLowResolutionWidth;
- config.blending = SvQuality::LOW;
- if (surroundView2dSession->set2dConfig(config) != SvResult::OK) {
- LOG(ERROR) << "Failed to set2dConfig";
- return false;
- }
-
- // Let the SV algorithm run for 10 seconds for LOW_QUALITY
- std::this_thread::sleep_for(std::chrono::seconds(10));
-
- // TODO(b/150412555): wait for the last frame
- // Stop the 2d stream and session
- surroundView2dSession->stopStream();
-
- pSurroundViewService->stop2dSession(surroundView2dSession);
- surroundView2dSession = nullptr;
-
- LOG(INFO) << "SV 2D session finished.";
-
- return true;
-};
-
-// Given a valid sv 3d session and pose, viewid and hfov parameters, sets the view.
-bool setView(sp<ISurroundView3dSession> surroundView3dSession, uint32_t viewId,
- uint32_t poseIndex, float hfov)
-{
- const View3d view3d = {
- .viewId = viewId,
- .pose = {
- .rotation = {.x=kPoseRot[poseIndex][0], .y=kPoseRot[poseIndex][1],
- .z=kPoseRot[poseIndex][2], .w=kPoseRot[poseIndex][3]},
- .translation = {.x=kPoseTrans[poseIndex][0], .y=kPoseTrans[poseIndex][1],
- .z=kPoseTrans[poseIndex][2]},
- },
- .horizontalFov = hfov,
- };
-
- const std::vector<View3d> views = {view3d};
- if (surroundView3dSession->setViews(views) != SvResult::OK) {
- return false;
- }
- return true;
-}
-
-bool run3dSurroundView(sp<ISurroundViewService> pSurroundViewService,
- sp<IEvsDisplay> pDisplay) {
- LOG(INFO) << "Run 3d Surround View demo";
-
- // Call HIDL API "start3dSession"
- sp<ISurroundView3dSession> surroundView3dSession;
-
- SvResult svResult;
- pSurroundViewService->start3dSession(
- [&surroundView3dSession, &svResult](
- const sp<ISurroundView3dSession>& session, SvResult result) {
- surroundView3dSession = session;
- svResult = result;
- });
-
- if (surroundView3dSession == nullptr || svResult != SvResult::OK) {
- LOG(ERROR) << "Failed to start3dSession";
- return false;
- } else {
- LOG(INFO) << "start3dSession succeeded";
- }
-
- sp<SurroundViewServiceCallback> sv3dCallback
- = new SurroundViewServiceCallback(pDisplay, surroundView3dSession);
-
- // A view must be set before the 3d stream is started.
- if (!setView(surroundView3dSession, 0, 0, kHorizontalFov)) {
- LOG(ERROR) << "Failed to setView of pose index :" << 0;
- return false;
- }
-
- // Start 3d stream with callback
- if (surroundView3dSession->startStream(sv3dCallback) != SvResult::OK) {
- LOG(ERROR) << "Failed to start 3d stream";
- return false;
- }
-
- // Let the SV algorithm run for 10 seconds for HIGH_QUALITY
- const int totalViewingTimeSecs = 10;
- const std::chrono::milliseconds
- perPoseSleepTimeMs(totalViewingTimeSecs * 1000 / kPoseCount);
- for(uint32_t i = 1; i < kPoseCount; i++) {
- if (!setView(surroundView3dSession, i, i, kHorizontalFov)) {
- LOG(WARNING) << "Failed to setView of pose index :" << i;
- }
- std::this_thread::sleep_for(perPoseSleepTimeMs);
- }
-
- // Switch to low quality and lower resolution
- Sv3dConfig config;
- config.width = kLowResolutionWidth;
- config.height = kLowResolutionHeight;
- config.carDetails = SvQuality::LOW;
- if (surroundView3dSession->set3dConfig(config) != SvResult::OK) {
- LOG(ERROR) << "Failed to set3dConfig";
- return false;
- }
-
- // Let the SV algorithm run for 10 seconds for LOW_QUALITY
- for(uint32_t i = 0; i < kPoseCount; i++) {
- if(!setView(surroundView3dSession, i + kPoseCount, i, kHorizontalFov)) {
- LOG(WARNING) << "Failed to setView of pose index :" << i;
- }
- std::this_thread::sleep_for(perPoseSleepTimeMs);
- }
-
- // TODO(b/150412555): wait for the last frame
- // Stop the 3d stream and session
- surroundView3dSession->stopStream();
-
- pSurroundViewService->stop3dSession(surroundView3dSession);
- surroundView3dSession = nullptr;
-
- LOG(DEBUG) << "SV 3D session finished.";
-
- return true;
-};
+using namespace android::hardware::automotive::sv::app;
// Main entry point
int main(int argc, char** argv) {
diff --git a/cpp/surround_view/service-impl/SurroundView2dSession.cpp b/cpp/surround_view/service-impl/SurroundView2dSession.cpp
index a92372c..2d837e0 100644
--- a/cpp/surround_view/service-impl/SurroundView2dSession.cpp
+++ b/cpp/surround_view/service-impl/SurroundView2dSession.cpp
@@ -53,6 +53,9 @@
namespace V1_0 {
namespace implementation {
+// Macro for obtaining a uint64_t memory_id from the camera index and buffer_id.
+#define GET_MEMORY_ID(cam_index, buffer_id) ((static_cast<uint64_t>(cam_index) << 32) | buffer_id)
+
// TODO(b/158479099): There are a lot of redundant code between 2d and 3d.
// Decrease the degree of redundancy.
typedef struct {
@@ -153,6 +156,10 @@
}
mSession->mInputPointers[i].gpu_data_pointer = static_cast<void*>(hardwareBuffer);
+ // Set memory_id to enable buffer caching.
+ // higher 32 bits are for camera index, lower 32 bits for bufferId.
+ mSession->mInputPointers[i].memory_id
+ = GET_MEMORY_ID(indices[i], buffers[indices[i]].bufferId);
// Keep a reference to the EVS graphic buffers, so we can
// release them after Surround View stitching is done.
@@ -747,6 +754,9 @@
return false;
}
mOutputPointer.gpu_data_pointer = static_cast<void*>(mOutputHolder->toAHardwareBuffer());
+ // Set output memory id one time to a one time unique value.
+ // 0 to (kNumFrames - 1) are used for inputs, using kNumFrames as higher 32 bits.
+ mOutputPointer.memory_id = GET_MEMORY_ID(kNumFrames, 0x00);
} else {
mSvTexture = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGB_888, 1,
GRALLOC_USAGE_HW_TEXTURE, "SvTexture");
diff --git a/cpp/surround_view/service-impl/core_lib.h b/cpp/surround_view/service-impl/core_lib.h
index fd8f1ec..a149f86 100644
--- a/cpp/surround_view/service-impl/core_lib.h
+++ b/cpp/surround_view/service-impl/core_lib.h
@@ -670,29 +670,54 @@
car_parts(parts) {}
};
+// Constant used as an invalid memory id for SurroundViewInputBufferPointers and
+// SurroundViewResultPointer. Setting to `memory_id` to kInvalidMemoryId implies
+// no caching is performed.
+const uint64_t kInvalidMemoryId = UINT64_MAX;
+
+// Currently we keep both cpu and gpu data pointers, and only one of them should
+// be valid at a certain point. Also, users are responsible to allocate and
+// de-allocate the pointers.
+// TODO(b/174778117): consider use only one data pointer once GPU migration is
+// done.
+// TODO(b/184870125): Consider merging with SurroundViewInputBufferPointers.
struct SurroundViewInputBufferPointers {
void* gpu_data_pointer;
void* cpu_data_pointer;
Format format;
int width;
int height;
+ // Unique identifier for the CPU/GPU data buffer. If memory id is the same as
+ // a previously provided input buffer, cached intermediate allocated data will
+ // be used for faster operation. If `memory_id` is kInvalidMemoryId no caching
+ // is performed. Currently supported: SV2D GPU pipeline with
+ // `gpu_data_pointer`.
+ // Recommend the `memory_id` provided by client to be created as:
+ // ((camera_index) << 32 ) | (graphics_buffer_id).
+ uint64_t memory_id;
SurroundViewInputBufferPointers() :
- gpu_data_pointer(nullptr), cpu_data_pointer(nullptr), width(0), height(0) {}
+ gpu_data_pointer(nullptr),
+ cpu_data_pointer(nullptr),
+ width(0),
+ height(0),
+ memory_id(kInvalidMemoryId) {}
SurroundViewInputBufferPointers(void* gpu_data_pointer_, void* cpu_data_pointer_,
- Format format_, int width_, int height_) :
+ Format format_, int width_, int height_,
+ uint64_t memory_id_ = kInvalidMemoryId) :
gpu_data_pointer(gpu_data_pointer_),
cpu_data_pointer(cpu_data_pointer_),
format(format_),
width(width_),
- height(height_) {}
+ height(height_),
+ memory_id(memory_id_) {}
};
// Currently we keep both cpu and gpu data pointers, and only one of them should
// be valid at a certain point. Users need to check null before they make use of
// the data pointers.
// TODO(b/174778117): consider use only one data pointer once GPU migration is
-// done. If we are going to keep both cpu and gpu data pointer, specify the type
-// of data for cpu data pointer, instead of using a void pointer.
+// done.
+// TODO(b/184870125): Consider merging with SurroundViewInputBufferPointers.
struct SurroundViewResultPointer {
void* gpu_data_pointer;
void* cpu_data_pointer;
@@ -700,24 +725,32 @@
int width;
int height;
bool is_data_preallocated;
+ // Unique identifier for the CPU/GPU data buffer. If memory id is the same as
+ // a previously provided result buffer, cached intermediate allocated data
+ // will be used for faster operation. If memory_id is kInvalidMemoryId no
+ // caching is performed. Currently supported: SV2D GPU pipeline with
+ // 'gpu_data_pointer'.
+ // Recommend the `memory_id` provided by client to be created as:
+ // ((camera_index) << 32 ) | (graphics_buffer_id).
+ uint64_t memory_id;
SurroundViewResultPointer() :
gpu_data_pointer(nullptr),
cpu_data_pointer(nullptr),
width(0),
height(0),
- is_data_preallocated(false) {}
+ is_data_preallocated(false),
+ memory_id(kInvalidMemoryId) {}
- // Constructor with result data pointer being allocated within core lib.
+ // Constructor with result cpu data pointer being allocated within core lib.
// Use for cases when no already existing buffer is available.
SurroundViewResultPointer(Format format_, int width_, int height_) :
- gpu_data_pointer(nullptr),
- format(format_),
- width(width_),
- height(height_),
- is_data_preallocated(false) {
+ format(format_), width(width_), height(height_) {
// default formate is gray.
const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
cpu_data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
+ gpu_data_pointer = nullptr;
+ is_data_preallocated = false;
+ memory_id = kInvalidMemoryId;
}
// Constructor with pre-allocated data.
@@ -730,7 +763,8 @@
format(format_),
width(width_),
height(height_),
- is_data_preallocated(true) {}
+ is_data_preallocated(true),
+ memory_id(kInvalidMemoryId) {}
~SurroundViewResultPointer() {
if (cpu_data_pointer) {
diff --git a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
index 4dfc535..8422731 100755
--- a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ b/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/cpp/telemetry/ARCHITECTURE.md b/cpp/telemetry/ARCHITECTURE.md
new file mode 100644
index 0000000..75dd194
--- /dev/null
+++ b/cpp/telemetry/ARCHITECTURE.md
@@ -0,0 +1,22 @@
+# Architecture of Car Telemetry Service
+
+## Names
+
+- C++ namespace `android.automotive.telemetry` - for all the car telemetry related projects.
+- android.telemetry.ICarTelemetry - AIDL interface for collecting car data.
+- cartelemetryd (android.automotive.telemetryd) - a daemon that implements `ICarTelemetry`
+ interface.
+- CarTelemetryService - a part of CarService that executes scrits. Located in car services dir.
+
+## Structure
+
+```
+aidl/ - Internal AIDL declerations, for public AIDLs, please see
+ //frameworks/hardware/interfaces/automotive/telemetry
+products/ - AAOS Telemetry product, it's included in car_base.mk
+sepolicy - SELinux policies
+src/ - Source code
+ TelemetryServer.h - The main class.
+*.rc - rc file to start services
+*.xml - VINTF manifest (TODO: needed?)
+```
diff --git a/cpp/telemetry/Android.bp b/cpp/telemetry/Android.bp
new file mode 100644
index 0000000..4e6c1c0
--- /dev/null
+++ b/cpp/telemetry/Android.bp
@@ -0,0 +1,94 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+ name: "cartelemetryd_defaults",
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-unused-parameter",
+ ],
+ shared_libs: [
+ "android.automotive.telemetry.internal-ndk_platform",
+ "android.frameworks.automotive.telemetry-V1-ndk_platform",
+ "libbase",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ ],
+ product_variables: {
+ debuggable: {
+ cflags: [
+ "-DCARTELEMETRYD_DEBUG=true",
+ ]
+ }
+ },
+}
+
+cc_library {
+ name: "android.automotive.telemetryd@1.0-impl",
+ defaults: [
+ "cartelemetryd_defaults",
+ ],
+ srcs: [
+ "src/CarTelemetryImpl.cpp",
+ "src/CarTelemetryInternalImpl.cpp",
+ "src/RingBuffer.cpp",
+ "src/TelemetryServer.cpp",
+ ],
+ // Allow dependents to use the header files.
+ export_include_dirs: [
+ "src",
+ ],
+}
+
+cc_test {
+ name: "cartelemetryd_impl_test",
+ defaults: [
+ "cartelemetryd_defaults",
+ ],
+ test_suites: ["general-tests"],
+ srcs: [
+ "tests/CarTelemetryImplTest.cpp",
+ "tests/CarTelemetryInternalImplTest.cpp",
+ "tests/RingBufferTest.cpp",
+ ],
+ // Statically link only in tests, for portability reason.
+ static_libs: [
+ "android.automotive.telemetryd@1.0-impl",
+ "android.automotive.telemetry.internal-ndk_platform",
+ "android.frameworks.automotive.telemetry-V1-ndk_platform",
+ "libgmock",
+ "libgtest",
+ ],
+}
+
+cc_binary {
+ name: "android.automotive.telemetryd@1.0",
+ defaults: [
+ "cartelemetryd_defaults",
+ ],
+ srcs: [
+ "src/main.cpp"
+ ],
+ init_rc: ["android.automotive.telemetryd@1.0.rc"],
+ vintf_fragments: ["android.automotive.telemetryd@1.0.xml"],
+ shared_libs: [
+ "android.automotive.telemetryd@1.0-impl"
+ ],
+}
diff --git a/cpp/telemetry/OWNERS b/cpp/telemetry/OWNERS
new file mode 100644
index 0000000..80794e1
--- /dev/null
+++ b/cpp/telemetry/OWNERS
@@ -0,0 +1,3 @@
+sgurun@google.com
+zhomart@google.com
+mdashouk@google.com
diff --git a/cpp/telemetry/README.md b/cpp/telemetry/README.md
new file mode 100644
index 0000000..a13116d
--- /dev/null
+++ b/cpp/telemetry/README.md
@@ -0,0 +1,19 @@
+# Automotive Telemetry Service
+
+A structured log collection service for CarTelemetryService. See ARCHITECTURE.md to learn internals.
+
+## Useful Commands
+
+**Dump service information**
+
+`adb shell dumpsys android.automotive.telemetry.internal.ICarTelemetryInternal/default`
+
+**Starting emulator**
+
+`aae emulator run -selinux permissive -writable-system`
+
+**Running tests**
+
+`atest cartelemetryd_impl_test:CarTelemetryInternalImplTest#TestSetListenerReturnsOk`
+
+`atest cartelemetryd_impl_test`
diff --git a/cpp/telemetry/aidl/Android.bp b/cpp/telemetry/aidl/Android.bp
new file mode 100644
index 0000000..b4cd9c7
--- /dev/null
+++ b/cpp/telemetry/aidl/Android.bp
@@ -0,0 +1,35 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.automotive.telemetry.internal",
+ unstable: true,
+ vendor_available: false,
+ srcs: [
+ "android/automotive/telemetry/internal/*.aidl",
+ ],
+ backend: {
+ ndk: {
+ enabled: true,
+ },
+ java: {
+ platform_apis: true,
+ enabled: true,
+ },
+ }
+}
diff --git a/cpp/telemetry/aidl/android/automotive/telemetry/internal/CarDataInternal.aidl b/cpp/telemetry/aidl/android/automotive/telemetry/internal/CarDataInternal.aidl
new file mode 100644
index 0000000..bf31169
--- /dev/null
+++ b/cpp/telemetry/aidl/android/automotive/telemetry/internal/CarDataInternal.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 android.automotive.telemetry.internal;
+
+/**
+ * Wrapper for {@code android.frameworks.automotive.telemetry.CarData}.
+ */
+parcelable CarDataInternal {
+ /**
+ * Must be a valid id. Scripts subscribe to data using this id.
+ */
+ int id;
+
+ /**
+ * Content corresponding to the schema defined by the id.
+ */
+ byte[] content;
+}
diff --git a/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarDataListener.aidl b/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarDataListener.aidl
new file mode 100644
index 0000000..48ab6f9
--- /dev/null
+++ b/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarDataListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.automotive.telemetry.internal;
+
+import android.automotive.telemetry.internal.CarDataInternal;
+
+/**
+ * Listener for {@code ICarTelemetryInternal#registerListener}.
+ */
+oneway interface ICarDataListener {
+ /**
+ * Called by ICarTelemetry when the data are available to be consumed. ICarTelemetry removes
+ * the delivered data when the callback succeeds.
+ *
+ * <p>If the collected data is too large, it will send only chunk of the data, and the callback
+ * will be fired again.
+ *
+ * @param dataList the pushed data.
+ */
+ void onCarDataReceived(in CarDataInternal[] dataList);
+}
diff --git a/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl b/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
new file mode 100644
index 0000000..b8938ff
--- /dev/null
+++ b/cpp/telemetry/aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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 android.automotive.telemetry.internal;
+
+import android.automotive.telemetry.internal.ICarDataListener;
+
+/**
+ * An internal API provided by cartelemetryd for receiving the collected data.
+ */
+interface ICarTelemetryInternal {
+ /**
+ * Sets a listener for CarData. If there are existing CarData in the buffer, the daemon will
+ * start pushing them to the listener. There can be only a single registered listener at a time.
+ *
+ * @param listener the only listener.
+ * @throws IllegalStateException if someone is already registered or the listener is dead.
+ */
+ void setListener(in ICarDataListener listener);
+
+ /**
+ * Clears the listener if exists. Silently ignores if there is no listener.
+ */
+ void clearListener();
+}
diff --git a/cpp/telemetry/android.automotive.telemetryd@1.0.rc b/cpp/telemetry/android.automotive.telemetryd@1.0.rc
new file mode 100644
index 0000000..1513fa8
--- /dev/null
+++ b/cpp/telemetry/android.automotive.telemetryd@1.0.rc
@@ -0,0 +1,9 @@
+service cartelemetryd_service /system/bin/android.automotive.telemetryd@1.0
+ class core
+ user system
+ group system
+ disabled # starts below on early-init
+
+on early-init
+ # Start the service only after initializing the properties.
+ start cartelemetryd_service
diff --git a/cpp/telemetry/android.automotive.telemetryd@1.0.xml b/cpp/telemetry/android.automotive.telemetryd@1.0.xml
new file mode 100644
index 0000000..8156466
--- /dev/null
+++ b/cpp/telemetry/android.automotive.telemetryd@1.0.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 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.
+-->
+<!-- Required VINTF manifest for AIDL servers. -->
+<manifest version="1.0" type="framework">
+ <hal format="aidl">
+ <name>android.frameworks.automotive.telemetry</name>
+ <version>1</version>
+ <fqname>ICarTelemetry/default</fqname>
+ </hal>
+</manifest>
diff --git a/cpp/telemetry/products/telemetry.mk b/cpp/telemetry/products/telemetry.mk
new file mode 100644
index 0000000..634c9a9
--- /dev/null
+++ b/cpp/telemetry/products/telemetry.mk
@@ -0,0 +1,22 @@
+# 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.
+
+# cartelemetryd service
+PRODUCT_PACKAGES += android.automotive.telemetryd@1.0
+
+# Selinux public policies for cartelemetry
+PRODUCT_PUBLIC_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/sepolicy/public
+
+# Selinux private policies for cartelemetry
+PRODUCT_PRIVATE_SEPOLICY_DIRS += packages/services/Car/cpp/telemetry/sepolicy/private
diff --git a/cpp/telemetry/sampleclient/Android.bp b/cpp/telemetry/sampleclient/Android.bp
new file mode 100644
index 0000000..17fdee0
--- /dev/null
+++ b/cpp/telemetry/sampleclient/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+
+// Sample client for ICarTelemetry service.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "android.automotive.telemetryd-sampleclient",
+ srcs: [
+ "main.cpp",
+ ],
+ vendor: true,
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-unused-parameter",
+ ],
+ shared_libs: [
+ "android.frameworks.automotive.telemetry-V1-ndk_platform",
+ "libbase",
+ "libbinder_ndk",
+ "libutils",
+ ],
+}
diff --git a/cpp/telemetry/sampleclient/README.md b/cpp/telemetry/sampleclient/README.md
new file mode 100644
index 0000000..ebbaf16
--- /dev/null
+++ b/cpp/telemetry/sampleclient/README.md
@@ -0,0 +1,63 @@
+# ICarTelemetry Sample Client
+
+This is a sample vendor service that sends `CarData` to car telemetry service.
+
+## Running
+
+**1. Quick mode - under root**
+
+```
+m -j android.automotive.telemetryd-sampleclient
+
+adb remount # make sure run "adb disable-verity" before remounting
+adb push $ANDROID_PRODUCT_OUT/vendor/bin/android.automotive.telemetryd-sampleclient /system/bin/
+
+adb shell /system/bin/android.automotive.telemetryd-sampleclient
+
+# Then check logcat and dumpsys to verify the results.
+```
+
+**2. Under vendor**
+
+To include it in the final image, add
+`PRODUCT_PACKAGES += android.automotive.telemetryd-sampleclient` to
+`//packages/services/Car/cpp/telemetry/products/telemetry.mk` (or other suitable mk file).
+
+```
+# this goes to products/telemetry.mk
+
+PRODUCT_PACKAGES += android.automotive.telemetryd-sampleclient
+```
+
+The sampleclient doesn't automatically start during boot, to start manually, run:
+`adb shell /vendor/bin/android.automotive.telemetryd-sampleclient`.
+
+If you want to test it by running `init`, add these SELinux rules:
+
+```
+# this goes to sepolicy/private/cartelemetryd.te
+
+type cartelemetryd_sample, domain;
+type cartelemetryd_sample_exec, vendor_file_type, exec_type, file_type;
+init_daemon_domain(cartelemetryd_sample)
+```
+
+```
+# this goes to sepolicy/private/file_contexts
+
+/vendor/bin/android\.automotive\.telemetryd-sampleclient u:object_r:cartelemetryd_sample_exec:s0
+```
+
+And create an `.rc` file:
+
+```
+# File: cartelemetryd-sampleclient.rc
+# Don't forget to add `init_rc: ["cartelemetryd-sampleclient.rc"],` to the Android.bp
+
+service cartelemetryd_sample /vendor/bin/android.automotive.telemetryd-sampleclient
+ class hal
+ user system
+ group system
+ oneshot # run once, otherwise init keeps restarting it
+ disabled # do not start automatically
+```
diff --git a/cpp/telemetry/sampleclient/main.cpp b/cpp/telemetry/sampleclient/main.cpp
new file mode 100644
index 0000000..e45dc65
--- /dev/null
+++ b/cpp/telemetry/sampleclient/main.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "cartelemetryd_sample"
+
+#include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_manager.h>
+#include <utils/SystemClock.h>
+
+using ::aidl::android::frameworks::automotive::telemetry::CarData;
+using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
+using ::android::base::StringPrintf;
+
+int main(int argc, char* argv[]) {
+ const auto started_at_millis = android::elapsedRealtime();
+
+ // The name of the service is described in
+ // https://source.android.com/devices/architecture/aidl/aidl-hals#instance-names
+ const std::string instance = StringPrintf("%s/default", ICarTelemetry::descriptor);
+ LOG(INFO) << "Obtaining: " << instance;
+ std::shared_ptr<ICarTelemetry> service = ICarTelemetry::fromBinder(
+ ndk::SpAIBinder(AServiceManager_getService(instance.c_str())));
+ if (!service) {
+ LOG(ERROR) << "ICarTelemetry service not found, may be still initializing?";
+ return 1;
+ }
+
+ LOG(INFO) << "Building a CarData message, delta_since_start: "
+ << android::elapsedRealtime() - started_at_millis << " millis";
+
+ // Build a CarData message
+ // TODO(b/174608802): set a correct data ID and content
+ CarData msg;
+ msg.id = 101;
+ msg.content = {1, 0, 1, 0};
+
+ LOG(INFO) << "Sending the car data, delta_since_start: "
+ << android::elapsedRealtime() - started_at_millis << " millis";
+
+ // Send the data
+ ndk::ScopedAStatus writeStatus = service->write({msg});
+
+ if (!writeStatus.isOk()) {
+ LOG(WARNING) << "Failed to write to the service: " << writeStatus.getMessage();
+ }
+
+ // Note: On a device the delta_since_start was between 1ms to 4ms
+ // (service side was not fully implemented yet during the test).
+ LOG(INFO) << "Finished, delta_since_start: " << android::elapsedRealtime() - started_at_millis
+ << " millis";
+
+ return 0;
+}
diff --git a/cpp/telemetry/sampleinternalclient/Android.bp b/cpp/telemetry/sampleinternalclient/Android.bp
new file mode 100644
index 0000000..d04ac09
--- /dev/null
+++ b/cpp/telemetry/sampleinternalclient/Android.bp
@@ -0,0 +1,36 @@
+// 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.
+
+// Sample client for ICarTelemetry service.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "android.automotive.telemetryd-sampleinternalclient",
+ srcs: [
+ "main.cpp",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-unused-parameter",
+ ],
+ shared_libs: [
+ "android.automotive.telemetry.internal-ndk_platform",
+ "libbase",
+ "libbinder_ndk",
+ "libutils",
+ ],
+}
diff --git a/cpp/telemetry/sampleinternalclient/main.cpp b/cpp/telemetry/sampleinternalclient/main.cpp
new file mode 100644
index 0000000..06ca549
--- /dev/null
+++ b/cpp/telemetry/sampleinternalclient/main.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+// This is a sample reader client for ICarTelemetryInternal.
+// TODO(b/186017953): remove this client when CarTelemetryService is implemented.
+//
+// adb remount # make sure run "adb disable-verity" before remounting
+// adb push $ANDROID_PRODUCT_OUT/system/bin/android.automotive.telemetryd-sampleinternalclient
+// /system/bin/
+//
+// adb shell /system/bin/android.automotive.telemetryd-sampleinternalclient
+
+#define LOG_TAG "cartelemetryd_sampleint"
+
+#include <aidl/android/automotive/telemetry/internal/BnCarDataListener.h>
+#include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
+#include <aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
+using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
+using ::aidl::android::automotive::telemetry::internal::ICarDataListener;
+using ::aidl::android::automotive::telemetry::internal::ICarTelemetryInternal;
+using ::android::base::StringPrintf;
+
+class CarDataListenerImpl : public BnCarDataListener {
+public:
+ ::ndk::ScopedAStatus onCarDataReceived(
+ const std::vector<CarDataInternal>& in_dataList) override;
+};
+
+::ndk::ScopedAStatus CarDataListenerImpl::onCarDataReceived(
+ const std::vector<CarDataInternal>& dataList) {
+ LOG(INFO) << "Received data size = " << dataList.size();
+ for (const auto data : dataList) {
+ LOG(INFO) << "data.id = " << data.id;
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+int main(int argc, char* argv[]) {
+ // The name of the service is described in
+ // https://source.android.com/devices/architecture/aidl/aidl-hals#instance-names
+ const std::string instance = StringPrintf("%s/default", ICarTelemetryInternal::descriptor);
+ LOG(INFO) << "Obtaining: " << instance;
+ std::shared_ptr<ICarTelemetryInternal> service = ICarTelemetryInternal::fromBinder(
+ ndk::SpAIBinder(AServiceManager_getService(instance.c_str())));
+ if (!service) {
+ LOG(FATAL) << "ICarTelemetryInternal service not found, may be still initializing?";
+ }
+
+ LOG(INFO) << "Setting the listener";
+ std::shared_ptr<CarDataListenerImpl> listener = ndk::SharedRefBase::make<CarDataListenerImpl>();
+ auto status = service->setListener(listener);
+ if (!status.isOk()) {
+ LOG(FATAL) << "Failed to set the listener";
+ }
+
+ ::ABinderProcess_startThreadPool();
+ ::ABinderProcess_joinThreadPool();
+ return 1; // not reachable
+}
diff --git a/cpp/telemetry/sepolicy/private/cartelemetryd.te b/cpp/telemetry/sepolicy/private/cartelemetryd.te
new file mode 100644
index 0000000..3baefb1
--- /dev/null
+++ b/cpp/telemetry/sepolicy/private/cartelemetryd.te
@@ -0,0 +1,9 @@
+### See //system/sepolicy/public/te_macros to learn about some SELinux macros.
+
+type cartelemetryd_exec, system_file_type, exec_type, file_type;
+
+binder_use(cartelemetryd)
+
+add_service(cartelemetryd, cartelemetryd_service)
+
+init_daemon_domain(cartelemetryd)
diff --git a/cpp/telemetry/sepolicy/private/file_contexts b/cpp/telemetry/sepolicy/private/file_contexts
new file mode 100644
index 0000000..0b0915d
--- /dev/null
+++ b/cpp/telemetry/sepolicy/private/file_contexts
@@ -0,0 +1 @@
+/system/bin/android\.automotive\.telemetryd@1\.0 u:object_r:cartelemetryd_exec:s0
diff --git a/cpp/telemetry/sepolicy/private/service_contexts b/cpp/telemetry/sepolicy/private/service_contexts
new file mode 100644
index 0000000..f26b5f8
--- /dev/null
+++ b/cpp/telemetry/sepolicy/private/service_contexts
@@ -0,0 +1,2 @@
+android.frameworks.automotive.telemetry.ICarTelemetry/default u:object_r:cartelemetryd_service:s0
+android.automotive.telemetry.internal.ICarTelemetryInternal/default u:object_r:cartelemetryd_service:s0
diff --git a/cpp/telemetry/sepolicy/public/cartelemetryd.te b/cpp/telemetry/sepolicy/public/cartelemetryd.te
new file mode 100644
index 0000000..fab4d58
--- /dev/null
+++ b/cpp/telemetry/sepolicy/public/cartelemetryd.te
@@ -0,0 +1 @@
+type cartelemetryd, domain, coredomain;
diff --git a/cpp/telemetry/sepolicy/public/service.te b/cpp/telemetry/sepolicy/public/service.te
new file mode 100644
index 0000000..f0beee8
--- /dev/null
+++ b/cpp/telemetry/sepolicy/public/service.te
@@ -0,0 +1 @@
+type cartelemetryd_service, service_manager_type;
diff --git a/cpp/telemetry/src/BufferedCarData.h b/cpp/telemetry/src/BufferedCarData.h
new file mode 100644
index 0000000..0c6ff4d
--- /dev/null
+++ b/cpp/telemetry/src/BufferedCarData.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SRC_BUFFEREDCARDATA_H_
+#define CPP_TELEMETRY_SRC_BUFFEREDCARDATA_H_
+
+#include <stdint.h>
+
+#include <tuple>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+// Internally stored `CarData` with some extras.
+struct BufferedCarData {
+ BufferedCarData(BufferedCarData&& other) = default;
+ BufferedCarData(const BufferedCarData&) = default;
+ BufferedCarData& operator=(BufferedCarData&& other) = default;
+ BufferedCarData& operator=(const BufferedCarData&) = default;
+
+ inline bool operator==(const BufferedCarData& rhs) const {
+ return std::tie(mId, mContent, mPublisherUid) ==
+ std::tie(rhs.mId, rhs.mContent, rhs.mPublisherUid);
+ }
+
+ // Returns the size of the stored data. Note that it's not the exact size of the struct.
+ int32_t contentSizeInBytes() const { return mContent.size(); }
+
+ const int32_t mId;
+ const std::vector<uint8_t> mContent;
+
+ // The uid of the logging client.
+ const uid_t mPublisherUid;
+};
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SRC_BUFFEREDCARDATA_H_
diff --git a/cpp/telemetry/src/CarTelemetryImpl.cpp b/cpp/telemetry/src/CarTelemetryImpl.cpp
new file mode 100644
index 0000000..34a4e60
--- /dev/null
+++ b/cpp/telemetry/src/CarTelemetryImpl.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#include "CarTelemetryImpl.h"
+
+#include "BufferedCarData.h"
+
+#include <aidl/android/frameworks/automotive/telemetry/CarData.h>
+#include <android/binder_ibinder.h>
+
+#include <stdio.h>
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using ::aidl::android::frameworks::automotive::telemetry::CarData;
+
+CarTelemetryImpl::CarTelemetryImpl(RingBuffer* buffer) : mRingBuffer(buffer) {}
+
+// TODO(b/174608802): Add 10kb size check for the `dataList`, see the AIDL for the limits
+ndk::ScopedAStatus CarTelemetryImpl::write(const std::vector<CarData>& dataList) {
+ uid_t publisherUid = ::AIBinder_getCallingUid();
+ for (auto&& data : dataList) {
+ mRingBuffer->push({.mId = data.id,
+ .mContent = std::move(data.content),
+ .mPublisherUid = publisherUid});
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/src/CarTelemetryImpl.h b/cpp/telemetry/src/CarTelemetryImpl.h
new file mode 100644
index 0000000..a3bb6c1
--- /dev/null
+++ b/cpp/telemetry/src/CarTelemetryImpl.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SRC_CARTELEMETRYIMPL_H_
+#define CPP_TELEMETRY_SRC_CARTELEMETRYIMPL_H_
+
+#include "RingBuffer.h"
+
+#include <aidl/android/frameworks/automotive/telemetry/BnCarTelemetry.h>
+#include <aidl/android/frameworks/automotive/telemetry/CarData.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+// Implementation of android.frameworks.automotive.telemetry.ICarTelemetry.
+class CarTelemetryImpl : public aidl::android::frameworks::automotive::telemetry::BnCarTelemetry {
+public:
+ // Doesn't own `buffer`.
+ explicit CarTelemetryImpl(RingBuffer* buffer);
+
+ ndk::ScopedAStatus write(
+ const std::vector<aidl::android::frameworks::automotive::telemetry::CarData>& dataList)
+ override;
+
+private:
+ RingBuffer* mRingBuffer; // not owned
+};
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SRC_CARTELEMETRYIMPL_H_
diff --git a/cpp/telemetry/src/CarTelemetryInternalImpl.cpp b/cpp/telemetry/src/CarTelemetryInternalImpl.cpp
new file mode 100644
index 0000000..7a3b141
--- /dev/null
+++ b/cpp/telemetry/src/CarTelemetryInternalImpl.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include "CarTelemetryInternalImpl.h"
+
+#include <aidl/android/automotive/telemetry/internal/BnCarDataListener.h>
+#include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
+#include <aidl/android/automotive/telemetry/internal/ICarDataListener.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
+using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
+using ::aidl::android::automotive::telemetry::internal::ICarDataListener;
+using ::android::base::StringPrintf;
+
+CarTelemetryInternalImpl::CarTelemetryInternalImpl(RingBuffer* buffer) :
+ mRingBuffer(buffer),
+ mBinderDeathRecipient(
+ ::AIBinder_DeathRecipient_new(CarTelemetryInternalImpl::listenerBinderDied)) {}
+
+ndk::ScopedAStatus CarTelemetryInternalImpl::setListener(
+ const std::shared_ptr<ICarDataListener>& listener) {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+
+ if (mCarDataListener != nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(::EX_ILLEGAL_STATE,
+ "ICarDataListener is already set.");
+ }
+
+ // If passed a local binder, AIBinder_linkToDeath will do nothing and return
+ // STATUS_INVALID_OPERATION. We ignore this case because we only use local binders in tests
+ // where this is not an error.
+ if (listener->isRemote()) {
+ auto status = ndk::ScopedAStatus::fromStatus(
+ ::AIBinder_linkToDeath(listener->asBinder().get(), mBinderDeathRecipient.get(),
+ this));
+ if (!status.isOk()) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(::EX_ILLEGAL_STATE,
+ status.getMessage());
+ }
+ }
+
+ mCarDataListener = listener;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus CarTelemetryInternalImpl::clearListener() {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ if (mCarDataListener == nullptr) {
+ LOG(INFO) << __func__ << ": No ICarDataListener, ignoring the call";
+ return ndk::ScopedAStatus::ok();
+ }
+ auto status = ndk::ScopedAStatus::fromStatus(
+ ::AIBinder_unlinkToDeath(mCarDataListener->asBinder().get(),
+ mBinderDeathRecipient.get(), this));
+ if (!status.isOk()) {
+ LOG(WARNING) << __func__
+ << ": unlinkToDeath failed, continuing anyway: " << status.getMessage();
+ }
+ mCarDataListener = nullptr;
+ return ndk::ScopedAStatus::ok();
+}
+
+binder_status_t CarTelemetryInternalImpl::dump(int fd, const char** args, uint32_t numArgs) {
+ dprintf(fd, "ICarTelemetryInternal:\n");
+ mRingBuffer->dump(fd);
+ return ::STATUS_OK;
+}
+
+// Removes the listener if its binder dies.
+void CarTelemetryInternalImpl::listenerBinderDiedImpl() {
+ LOG(WARNING) << "A ICarDataListener died, removing the listener.";
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ mCarDataListener = nullptr;
+}
+
+void CarTelemetryInternalImpl::listenerBinderDied(void* cookie) {
+ auto thiz = static_cast<CarTelemetryInternalImpl*>(cookie);
+ thiz->listenerBinderDiedImpl();
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/src/CarTelemetryInternalImpl.h b/cpp/telemetry/src/CarTelemetryInternalImpl.h
new file mode 100644
index 0000000..12ad5cd
--- /dev/null
+++ b/cpp/telemetry/src/CarTelemetryInternalImpl.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SRC_CARTELEMETRYINTERNALIMPL_H_
+#define CPP_TELEMETRY_SRC_CARTELEMETRYINTERNALIMPL_H_
+
+#include "RingBuffer.h"
+
+#include <aidl/android/automotive/telemetry/internal/BnCarTelemetryInternal.h>
+#include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
+#include <aidl/android/automotive/telemetry/internal/ICarDataListener.h>
+#include <android/binder_status.h>
+#include <utils/Mutex.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+// Implementation of android.automotive.telemetry.ICarTelemetryInternal.
+class CarTelemetryInternalImpl :
+ public aidl::android::automotive::telemetry::internal::BnCarTelemetryInternal {
+public:
+ // Doesn't own `buffer`.
+ explicit CarTelemetryInternalImpl(RingBuffer* buffer);
+
+ ndk::ScopedAStatus setListener(
+ const std::shared_ptr<aidl::android::automotive::telemetry::internal::ICarDataListener>&
+ listener) override;
+
+ ndk::ScopedAStatus clearListener() override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+private:
+ // Death recipient callback that is called when ICarDataListener dies.
+ // The cookie is a pointer to a CarTelemetryInternalImpl object.
+ static void listenerBinderDied(void* cookie);
+
+ void listenerBinderDiedImpl();
+
+ RingBuffer* mRingBuffer; // not owned
+ ndk::ScopedAIBinder_DeathRecipient mBinderDeathRecipient;
+ std::mutex mMutex; // a mutex for the whole instance
+
+ std::shared_ptr<aidl::android::automotive::telemetry::internal::ICarDataListener>
+ mCarDataListener GUARDED_BY(mMutex);
+};
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SRC_CARTELEMETRYINTERNALIMPL_H_
diff --git a/cpp/telemetry/src/RingBuffer.cpp b/cpp/telemetry/src/RingBuffer.cpp
new file mode 100644
index 0000000..36de3f8
--- /dev/null
+++ b/cpp/telemetry/src/RingBuffer.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include "RingBuffer.h"
+
+#include <android-base/logging.h>
+
+#include <inttypes.h> // for PRIu64 and friends
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+RingBuffer::RingBuffer(int32_t limit) : mSizeLimit(limit) {}
+
+void RingBuffer::push(BufferedCarData&& data) {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ mList.push_back(std::move(data));
+ while (mList.size() > mSizeLimit) {
+ mList.pop_front();
+ mTotalDroppedDataCount += 1;
+ }
+}
+
+BufferedCarData RingBuffer::popFront() {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ auto result = std::move(mList.front());
+ mList.pop_front();
+ return result;
+}
+
+void RingBuffer::dump(int fd) const {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ dprintf(fd, "RingBuffer:\n");
+ dprintf(fd, " mSizeLimit=%d\n", mSizeLimit);
+ dprintf(fd, " mList.size=%zu\n", mList.size());
+ dprintf(fd, " mTotalDroppedDataCount=%" PRIu64 "\n", mTotalDroppedDataCount);
+}
+
+int32_t RingBuffer::size() const {
+ const std::scoped_lock<std::mutex> lock(mMutex);
+ return mList.size();
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/src/RingBuffer.h b/cpp/telemetry/src/RingBuffer.h
new file mode 100644
index 0000000..07ce709
--- /dev/null
+++ b/cpp/telemetry/src/RingBuffer.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SRC_RINGBUFFER_H_
+#define CPP_TELEMETRY_SRC_RINGBUFFER_H_
+
+#include "BufferedCarData.h"
+
+#include <list>
+#include <mutex>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+// A ring buffer that holds BufferedCarData. It drops old data if it's full.
+// Thread-safe.
+class RingBuffer {
+public:
+ // RingBuffer limits the number of elements in the buffer to the given param `sizeLimit`.
+ // Doesn't pre-allocate the memory.
+ explicit RingBuffer(int32_t sizeLimit);
+
+ // Not copyable or movable
+ RingBuffer(const RingBuffer&) = delete;
+ RingBuffer& operator=(const RingBuffer&) = delete;
+ RingBuffer(RingBuffer&&) = delete;
+ RingBuffer& operator=(RingBuffer&&) = delete;
+
+ // Pushes the data to the buffer. If the buffer is full, it removes the oldest data.
+ // Supports moving the data to the RingBuffer.
+ void push(BufferedCarData&& data);
+
+ // Returns the oldest element from the ring buffer and removes it from the buffer.
+ BufferedCarData popFront();
+
+ // Dumps the current state for dumpsys.
+ void dump(int fd) const;
+
+ // Returns the number of elements in the buffer.
+ int32_t size() const;
+
+private:
+ mutable std::mutex mMutex; // a mutex for the whole instance
+
+ const int32_t mSizeLimit;
+
+ // TODO(b/174608802): Improve dropped CarData handling, see ag/13818937 for details.
+ int64_t mTotalDroppedDataCount;
+
+ // Linked list that holds all the data and allows deleting old data when the buffer is full.
+ std::list<BufferedCarData> mList;
+};
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SRC_RINGBUFFER_H_
diff --git a/cpp/telemetry/src/TelemetryServer.cpp b/cpp/telemetry/src/TelemetryServer.cpp
new file mode 100644
index 0000000..54cd3c4
--- /dev/null
+++ b/cpp/telemetry/src/TelemetryServer.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include "TelemetryServer.h"
+
+#include "CarTelemetryImpl.h"
+#include "RingBuffer.h"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <inttypes.h> // for PRIu64 and friends
+
+#include <memory>
+#include <thread> // NOLINT(build/c++11)
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using ::android::automotive::telemetry::RingBuffer;
+
+constexpr const char kCarTelemetryServiceName[] =
+ "android.frameworks.automotive.telemetry.ICarTelemetry/default";
+constexpr const char kCarTelemetryInternalServiceName[] =
+ "android.automotive.telemetry.internal.ICarTelemetryInternal/default";
+
+// TODO(b/183444070): make it configurable using sysprop
+// CarData count limit in the RingBuffer. In worst case it will use kMaxBufferSize * 10Kb memory,
+// which is ~ 1MB.
+const int kMaxBufferSize = 100;
+
+TelemetryServer::TelemetryServer() : mRingBuffer(kMaxBufferSize) {}
+
+void TelemetryServer::registerServices() {
+ std::shared_ptr<CarTelemetryImpl> telemetry =
+ ndk::SharedRefBase::make<CarTelemetryImpl>(&mRingBuffer);
+ std::shared_ptr<CarTelemetryInternalImpl> telemetryInternal =
+ ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&mRingBuffer);
+
+ // Wait for the service manager before starting ICarTelemetry service.
+ while (android::base::GetProperty("init.svc.servicemanager", "") != "running") {
+ // Poll frequent enough so the writer clients can connect to the service during boot.
+ std::this_thread::sleep_for(250ms);
+ }
+
+ LOG(VERBOSE) << "Registering " << kCarTelemetryServiceName;
+ binder_exception_t exception =
+ ::AServiceManager_addService(telemetry->asBinder().get(), kCarTelemetryServiceName);
+ if (exception != ::EX_NONE) {
+ LOG(FATAL) << "Unable to register " << kCarTelemetryServiceName
+ << ", exception=" << exception;
+ }
+
+ LOG(VERBOSE) << "Registering " << kCarTelemetryInternalServiceName;
+ exception = ::AServiceManager_addService(telemetryInternal->asBinder().get(),
+ kCarTelemetryInternalServiceName);
+ if (exception != ::EX_NONE) {
+ LOG(FATAL) << "Unable to register " << kCarTelemetryInternalServiceName
+ << ", exception=" << exception;
+ }
+}
+
+void TelemetryServer::startAndJoinThreadPool() {
+ ::ABinderProcess_startThreadPool(); // Starts the default 15 binder threads.
+ ::ABinderProcess_joinThreadPool();
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/src/TelemetryServer.h b/cpp/telemetry/src/TelemetryServer.h
new file mode 100644
index 0000000..0b400a1
--- /dev/null
+++ b/cpp/telemetry/src/TelemetryServer.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_TELEMETRY_SRC_TELEMETRYSERVER_H_
+#define CPP_TELEMETRY_SRC_TELEMETRYSERVER_H_
+
+#include "CarTelemetryImpl.h"
+#include "CarTelemetryInternalImpl.h"
+
+#include <utils/Errors.h>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+class TelemetryServer {
+public:
+ TelemetryServer();
+
+ // Registers all the implemented AIDL services. Waits until `servicemanager` is available.
+ // Aborts the process if fails.
+ void registerServices();
+
+ // Blocks the thread.
+ void startAndJoinThreadPool();
+
+private:
+ RingBuffer mRingBuffer;
+};
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SRC_TELEMETRYSERVER_H_
diff --git a/cpp/telemetry/src/main.cpp b/cpp/telemetry/src/main.cpp
new file mode 100644
index 0000000..1bd0dde
--- /dev/null
+++ b/cpp/telemetry/src/main.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include "TelemetryServer.h"
+
+#include <android-base/logging.h>
+
+using ::android::automotive::telemetry::TelemetryServer;
+
+// TODO(b/174608802): handle SIGQUIT/SIGTERM
+
+int main(void) {
+ LOG(INFO) << "Starting cartelemetryd";
+
+ TelemetryServer server;
+
+ // Register AIDL services. Aborts the server if fails.
+ server.registerServices();
+
+ LOG(VERBOSE) << "Service is created, joining the threadpool";
+ server.startAndJoinThreadPool();
+ return 1; // never reaches
+}
diff --git a/cpp/telemetry/tests/CarTelemetryImplTest.cpp b/cpp/telemetry/tests/CarTelemetryImplTest.cpp
new file mode 100644
index 0000000..0286477
--- /dev/null
+++ b/cpp/telemetry/tests/CarTelemetryImplTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 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.
+ */
+
+#include "CarTelemetryImpl.h"
+#include "RingBuffer.h"
+
+#include <aidl/android/frameworks/automotive/telemetry/CarData.h>
+#include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <unistd.h>
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using ::aidl::android::frameworks::automotive::telemetry::CarData;
+using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
+using ::testing::ContainerEq;
+
+const size_t kMaxBufferSize = 5;
+
+CarData buildCarData(int id, const std::vector<uint8_t>& content) {
+ CarData msg;
+ msg.id = id;
+ msg.content = content;
+ return msg;
+}
+
+BufferedCarData buildBufferedCarData(const CarData& data, uid_t publisherUid) {
+ return {.mId = data.id, .mContent = std::move(data.content), .mPublisherUid = publisherUid};
+}
+
+class CarTelemetryImplTest : public ::testing::Test {
+protected:
+ CarTelemetryImplTest() :
+ mBuffer(RingBuffer(kMaxBufferSize)),
+ mTelemetry(ndk::SharedRefBase::make<CarTelemetryImpl>(&mBuffer)) {}
+
+ RingBuffer mBuffer;
+ std::shared_ptr<ICarTelemetry> mTelemetry;
+};
+
+TEST_F(CarTelemetryImplTest, WriteReturnsOkStatus) {
+ CarData msg = buildCarData(101, {1, 0, 1, 0});
+
+ auto status = mTelemetry->write({msg});
+
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(CarTelemetryImplTest, WriteAddsCarDataToRingBuffer) {
+ CarData msg = buildCarData(101, {1, 0, 1, 0});
+
+ mTelemetry->write({msg});
+
+ EXPECT_EQ(mBuffer.popFront(), buildBufferedCarData(msg, getuid()));
+}
+
+TEST_F(CarTelemetryImplTest, WriteBuffersOnlyLimitedAmount) {
+ RingBuffer buffer(/* sizeLimit= */ 3);
+ auto telemetry = ndk::SharedRefBase::make<CarTelemetryImpl>(&buffer);
+
+ CarData msg101_2 = buildCarData(101, {1, 0});
+ CarData msg101_4 = buildCarData(101, {1, 0, 1, 0});
+ CarData msg201_3 = buildCarData(201, {3, 3, 3});
+
+ // Inserting 5 elements
+ telemetry->write({msg101_2, msg101_4, msg101_4, msg201_3});
+ telemetry->write({msg201_3});
+
+ EXPECT_EQ(buffer.size(), 3);
+ std::vector<BufferedCarData> result = {buffer.popFront(), buffer.popFront(), buffer.popFront()};
+ std::vector<BufferedCarData> expected = {buildBufferedCarData(msg101_4, getuid()),
+ buildBufferedCarData(msg201_3, getuid()),
+ buildBufferedCarData(msg201_3, getuid())};
+ EXPECT_THAT(result, ContainerEq(expected));
+ EXPECT_EQ(buffer.size(), 0);
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/tests/CarTelemetryInternalImplTest.cpp b/cpp/telemetry/tests/CarTelemetryInternalImplTest.cpp
new file mode 100644
index 0000000..22838cd
--- /dev/null
+++ b/cpp/telemetry/tests/CarTelemetryInternalImplTest.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 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.
+ */
+
+#include "CarTelemetryInternalImpl.h"
+#include "RingBuffer.h"
+
+#include <aidl/android/automotive/telemetry/internal/BnCarDataListener.h>
+#include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
+#include <aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <unistd.h>
+
+#include <memory>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
+using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
+using ::aidl::android::automotive::telemetry::internal::ICarTelemetryInternal;
+using ::ndk::ScopedAStatus;
+
+const size_t kMaxBufferSize = 5;
+
+class MockCarDataListener : public BnCarDataListener {
+public:
+ MOCK_METHOD(ScopedAStatus, onCarDataReceived, (const std::vector<CarDataInternal>& dataList),
+ (override));
+};
+
+// The main test class.
+class CarTelemetryInternalImplTest : public ::testing::Test {
+protected:
+ CarTelemetryInternalImplTest() :
+ mBuffer(RingBuffer(kMaxBufferSize)),
+ mTelemetryInternal(ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&mBuffer)),
+ mMockCarDataListener(ndk::SharedRefBase::make<MockCarDataListener>()) {}
+
+ RingBuffer mBuffer;
+ std::shared_ptr<ICarTelemetryInternal> mTelemetryInternal;
+ std::shared_ptr<MockCarDataListener> mMockCarDataListener;
+};
+
+TEST_F(CarTelemetryInternalImplTest, SetListenerReturnsOk) {
+ auto status = mTelemetryInternal->setListener(mMockCarDataListener);
+
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+}
+
+TEST_F(CarTelemetryInternalImplTest, SetListenerFailsWhenAlreadySubscribed) {
+ mTelemetryInternal->setListener(mMockCarDataListener);
+
+ auto status = mTelemetryInternal->setListener(ndk::SharedRefBase::make<MockCarDataListener>());
+
+ EXPECT_EQ(status.getExceptionCode(), ::EX_ILLEGAL_STATE) << status.getMessage();
+}
+
+TEST_F(CarTelemetryInternalImplTest, ClearListenerWorks) {
+ mTelemetryInternal->setListener(mMockCarDataListener);
+
+ mTelemetryInternal->clearListener();
+ auto status = mTelemetryInternal->setListener(mMockCarDataListener);
+
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/tests/RingBufferTest.cpp b/cpp/telemetry/tests/RingBufferTest.cpp
new file mode 100644
index 0000000..c5b5bc7
--- /dev/null
+++ b/cpp/telemetry/tests/RingBufferTest.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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.
+ */
+
+#include "RingBuffer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+// NOTE: many of RingBuffer's behaviors are tested as part of CarTelemetryImpl.
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+
+using testing::ContainerEq;
+
+BufferedCarData buildBufferedCarData(int32_t id, const std::vector<uint8_t>& content) {
+ return {.mId = id, .mContent = content, .mPublisherUid = 0};
+}
+
+TEST(RingBufferTest, PopFrontReturnsCorrectResults) {
+ RingBuffer buffer(/* sizeLimit= */ 10);
+ buffer.push(buildBufferedCarData(101, {7}));
+ buffer.push(buildBufferedCarData(102, {7}));
+
+ BufferedCarData result = buffer.popFront();
+
+ EXPECT_EQ(result, buildBufferedCarData(101, {7}));
+}
+
+TEST(RingBufferTest, PopFrontRemovesFromBuffer) {
+ RingBuffer buffer(/* sizeLimit= */ 10);
+ buffer.push(buildBufferedCarData(101, {7}));
+ buffer.push(buildBufferedCarData(102, {7, 8}));
+
+ buffer.popFront();
+
+ EXPECT_EQ(buffer.size(), 1); // only ID=102 left
+}
+
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
index 7345448..57d82ca 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdog.aidl
@@ -19,8 +19,8 @@
import android.automotive.watchdog.internal.ComponentType;
import android.automotive.watchdog.internal.ICarWatchdogMonitor;
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
-import android.automotive.watchdog.internal.IoOveruseConfiguration;
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
+import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
import android.automotive.watchdog.internal.StateType;
/**
@@ -106,15 +106,20 @@
void notifySystemStateChange(in StateType type, in int arg1, in int arg2);
/**
- * CarWatchdogService uses this API to forward the I/O overuse configuration update received from
- * the system or OEM applications.
+ * Update the given resource overuse configurations.
* The caller should have system UID. Otherwise, returns security exception binder error.
*
- * @param type Component type for which the I/O overuse configuration update was
- * received.
- * @param config I/O overuse configuration.
+ * @param configs List of resource overuse configurations.
*/
- void updateIoOveruseConfiguration(in ComponentType type, in IoOveruseConfiguration config);
+ void updateResourceOveruseConfigurations(in List<ResourceOveruseConfiguration> configs);
+
+ /**
+ * Return the latest list of resource overuse configuration per component.
+ * The caller should have system UID. Otherwise, returns security exception binder error.
+ *
+ * @return configs List of resource overuse configurations.
+ */
+ List<ResourceOveruseConfiguration> getResourceOveruseConfigurations();
/**
* CarWatchdogService notifies the native service with the actions taken on the resource overusing
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
index 9aa234f..ef68dbc 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.aidl
@@ -52,7 +52,8 @@
* @param uids List of UIDs to resolve the package infos.
* @param vendorPackagePrefixes List of vendor package prefixes.
*/
- List<PackageInfo> getPackageInfosForUids(in int[] uids, in List<String> vendorPackagePrefixes);
+ List<PackageInfo> getPackageInfosForUids(
+ in int[] uids, in @utf8InCpp List<String> vendorPackagePrefixes);
/**
* Pushes the latest I/O overuse stats to the watchdog server.
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.aidl
index c2f0aec..7522a22 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/IoOveruseConfiguration.aidl
@@ -45,21 +45,8 @@
List<PerStateIoOveruseThreshold> categorySpecificThresholds;
/**
- * List of only non-critical system and vendor packages that are safe to kill on disk I/O
- * overuse. All third-party packages are considered safe to kill.
- */
- List<String> safeToKillPackages;
-
- /**
* Array of system-wide I/O overuse thresholds that triggers the system-wide disk I/O overuse
* alert. This must be defined only by the system component.
*/
List<IoOveruseAlertThreshold> systemWideThresholds;
-
- /**
- * Defines the list of vendor package prefixes. Any pre-installed package name starting with one
- * of these prefixes will be identified as a vendor package in addition to packages under the
- * vendor partition. This must be defined only by the vendor component.
- */
- List<String> vendorPackagePrefixes;
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
index fa6e36b..c0dd86e 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageIdentifier.aidl
@@ -23,7 +23,7 @@
/**
* Name of the package.
*/
- String name;
+ @utf8InCpp String name;
/**
* UID of the package.
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageInfo.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageInfo.aidl
index bd3dd1a..2deb5f3 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageInfo.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageInfo.aidl
@@ -38,7 +38,7 @@
/**
* List of packages owned by the package. This list is empty when the UID is not a shared UID.
*/
- List<String> sharedUidPackages;
+ @utf8InCpp List<String> sharedUidPackages;
/**
* Component type of the package and the owned packages.
@@ -48,5 +48,5 @@
/**
* Application category type of the package and the owned packages.
*/
- ApplicationCategoryType appCategoryType;
+ ApplicationCategoryType appCategoryType = ApplicationCategoryType.OTHERS;
}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageMetadata.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageMetadata.aidl
new file mode 100644
index 0000000..46e6693
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PackageMetadata.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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 android.automotive.watchdog.internal;
+
+import android.automotive.watchdog.internal.ApplicationCategoryType;
+
+/**
+ * Structure that describes the package metadata.
+ */
+parcelable PackageMetadata {
+ /**
+ * Name of the package.
+ */
+ @utf8InCpp String packageName;
+
+ /**
+ * Application category type of the package.
+ *
+ * This must be defined only by the system and vendor component configurations.
+ */
+ ApplicationCategoryType appCategoryType = ApplicationCategoryType.OTHERS;
+}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.aidl
index 00a3c93..65f50ce 100644
--- a/cpp/watchdog/aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.aidl
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/PerStateIoOveruseThreshold.aidl
@@ -29,7 +29,7 @@
* 2. package name for package specific thresholds.
* 3. string equivalent of ApplicationCategoryType enum for category specific thresholds.
*/
- String name;
+ @utf8InCpp String name;
/**
* Defines the I/O overuse thresholds for a package. The thresholds are defined in terms of
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.aidl
new file mode 100644
index 0000000..26ae106
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceOveruseConfiguration.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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 android.automotive.watchdog.internal;
+
+import android.automotive.watchdog.internal.ComponentType;
+import android.automotive.watchdog.internal.PackageMetadata;
+import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
+
+/**
+ * Structure that describes the resource overuse configuration for a component.
+ */
+parcelable ResourceOveruseConfiguration {
+ /**
+ * Type of the component.
+ */
+ ComponentType componentType;
+
+ /**
+ * List of only non-critical system and vendor packages that are safe to kill on disk I/O
+ * overuse. All third-party packages are considered safe to kill.
+ */
+ @utf8InCpp List<String> safeToKillPackages;
+
+ /**
+ * Defines the list of vendor package prefixes. Any pre-installed package name starting with one
+ * of these prefixes will be identified as a vendor package in addition to packages under the
+ * vendor partition. This must be defined only by the vendor component.
+ */
+ @utf8InCpp List<String> vendorPackagePrefixes;
+
+ /**
+ * Defines the package metadata.
+ */
+ List<PackageMetadata> packageMetadata;
+
+ /**
+ * Defines resource specific overuse configurations for the current component.
+ */
+ List<ResourceSpecificConfiguration> resourceSpecificConfigurations;
+}
diff --git a/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceSpecificConfiguration.aidl b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceSpecificConfiguration.aidl
new file mode 100644
index 0000000..34a8c92
--- /dev/null
+++ b/cpp/watchdog/aidl/android/automotive/watchdog/internal/ResourceSpecificConfiguration.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 android.automotive.watchdog.internal;
+
+import android.automotive.watchdog.internal.IoOveruseConfiguration;
+
+/**
+ * Overuse configuration interface for specific resource types.
+ */
+union ResourceSpecificConfiguration {
+ /**
+ * I/O overuse configuration.
+ */
+ IoOveruseConfiguration ioOveruseConfiguration;
+ // Overuse configuration for other resource types may be added in the future.
+}
diff --git a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
index 0f6cce1..57d18b0 100644
--- a/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
+++ b/cpp/watchdog/car-watchdog-lib/src/android/car/watchdoglib/CarWatchdogDaemonHelper.java
@@ -24,6 +24,7 @@
import android.automotive.watchdog.internal.ICarWatchdogMonitor;
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
+import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -34,6 +35,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -46,9 +48,11 @@
public final class CarWatchdogDaemonHelper {
private static final String TAG = CarWatchdogDaemonHelper.class.getSimpleName();
- // Carwatchdog daemon polls for the service manager status once every 250 milliseconds.
- // CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS value should be at least twice the poll interval
- // used by the daemon.
+ /*
+ * Car watchdog daemon polls for the service manager status once every 250 milliseconds.
+ * CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS value should be at least twice the poll interval
+ * used by the daemon.
+ */
private static final long CAR_WATCHDOG_DAEMON_BIND_RETRY_INTERVAL_MS = 500;
private static final long CAR_WATCHDOG_DAEMON_FIND_MARGINAL_TIME_MS = 300;
private static final int CAR_WATCHDOG_DAEMON_BIND_MAX_RETRY = 3;
@@ -250,10 +254,37 @@
}
/**
+ * Sets the given resource overuse configurations.
+ *
+ * @param configurations Resource overuse configuration per component type.
+ * @throws IllegalArgumentException If the configurations are invalid.
+ * @throws RemoteException
+ */
+ public void updateResourceOveruseConfigurations(
+ List<ResourceOveruseConfiguration> configurations) throws RemoteException {
+ invokeDaemonMethod((daemon) -> daemon.updateResourceOveruseConfigurations(configurations));
+ }
+
+ /**
+ * Returns the available resource overuse configurations.
+ *
+ * @throws RemoteException
+ */
+ public List<ResourceOveruseConfiguration> getResourceOveruseConfigurations()
+ throws RemoteException {
+ List<ResourceOveruseConfiguration> configurations = new ArrayList<>();
+ invokeDaemonMethod((daemon) -> {
+ configurations.addAll(daemon.getResourceOveruseConfigurations());
+ });
+ return configurations;
+ }
+
+ /**
* Notifies car watchdog daemon with the actions taken on resource overuse.
*
* @param actions List of actions taken on resource overuse. One action taken per resource
* overusing user package.
+ * @throws RemoteException
*/
public void actionTakenOnResourceOveruse(List<PackageResourceOveruseAction> actions)
throws RemoteException {
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.cpp b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
index 3c2cf3e..90a73df 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.cpp
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.cpp
@@ -21,7 +21,6 @@
#include "PackageInfoResolver.h"
#include <android-base/strings.h>
-#include <utils/String8.h>
#include <inttypes.h>
@@ -31,15 +30,16 @@
namespace automotive {
namespace watchdog {
-using ::android::String16;
-using ::android::String8;
using ::android::automotive::watchdog::PerStateBytes;
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
using ::android::automotive::watchdog::internal::PackageInfo;
+using ::android::automotive::watchdog::internal::PackageMetadata;
using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
using ::android::automotive::watchdog::internal::UidType;
using ::android::base::Error;
using ::android::base::Result;
@@ -50,24 +50,36 @@
namespace {
-// Enum to filter the updatable I/O overuse configs by each component.
-enum IoOveruseConfigEnum {
- COMPONENT_SPECIFIC_GENERIC_THRESHOLDS = 1 << 0,
- COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS = 1 << 1,
- COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES = 1 << 2,
- PER_CATEGORY_THRESHOLDS = 1 << 3,
- VENDOR_PACKAGE_PREFIXES = 1 << 4,
- SYSTEM_WIDE_ALERT_THRESHOLDS = 1 << 5,
+// Enum to filter the updatable overuse configs by each component.
+enum OveruseConfigEnum {
+ COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES = 1 << 0,
+ VENDOR_PACKAGE_PREFIXES = 1 << 1,
+ PACKAGE_APP_CATEGORY_MAPPINGS = 1 << 2,
+ COMPONENT_SPECIFIC_GENERIC_THRESHOLDS = 1 << 3,
+ COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS = 1 << 4,
+ PER_CATEGORY_THRESHOLDS = 1 << 5,
+ SYSTEM_WIDE_ALERT_THRESHOLDS = 1 << 6,
};
-const int32_t kSystemComponentUpdatableConfigs = COMPONENT_SPECIFIC_GENERIC_THRESHOLDS |
- COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
- SYSTEM_WIDE_ALERT_THRESHOLDS;
-const int32_t kVendorComponentUpdatableConfigs = COMPONENT_SPECIFIC_GENERIC_THRESHOLDS |
- COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
- PER_CATEGORY_THRESHOLDS | VENDOR_PACKAGE_PREFIXES;
+const int32_t kSystemComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
+ PACKAGE_APP_CATEGORY_MAPPINGS | COMPONENT_SPECIFIC_GENERIC_THRESHOLDS |
+ COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS | SYSTEM_WIDE_ALERT_THRESHOLDS;
+const int32_t kVendorComponentUpdatableConfigs = COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES |
+ VENDOR_PACKAGE_PREFIXES | PACKAGE_APP_CATEGORY_MAPPINGS |
+ COMPONENT_SPECIFIC_GENERIC_THRESHOLDS | COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS |
+ PER_CATEGORY_THRESHOLDS;
const int32_t kThirdPartyComponentUpdatableConfigs = COMPONENT_SPECIFIC_GENERIC_THRESHOLDS;
+const std::vector<std::string> toStringVector(const std::unordered_set<std::string>& values) {
+ std::vector<std::string> output;
+ for (const auto& v : values) {
+ if (!v.empty()) {
+ output.emplace_back(v);
+ }
+ }
+ return output;
+}
+
bool isZeroValueThresholds(const PerStateIoOveruseThreshold& thresholds) {
return thresholds.perStateWriteBytes.foregroundBytes == 0 &&
thresholds.perStateWriteBytes.backgroundBytes == 0 &&
@@ -77,14 +89,13 @@
std::string toString(const PerStateIoOveruseThreshold& thresholds) {
return StringPrintf("name=%s, foregroundBytes=%" PRId64 ", backgroundBytes=%" PRId64
", garageModeBytes=%" PRId64,
- String8(thresholds.name).c_str(),
- thresholds.perStateWriteBytes.foregroundBytes,
+ thresholds.name.c_str(), thresholds.perStateWriteBytes.foregroundBytes,
thresholds.perStateWriteBytes.backgroundBytes,
thresholds.perStateWriteBytes.garageModeBytes);
}
Result<void> containsValidThresholds(const PerStateIoOveruseThreshold& thresholds) {
- if (thresholds.name.size() == 0) {
+ if (thresholds.name.empty()) {
return Error() << "Doesn't contain threshold name";
}
@@ -122,28 +133,85 @@
Result<void> isValidIoOveruseConfiguration(const ComponentType componentType,
const int32_t updatableConfigsFilter,
- const IoOveruseConfiguration& updateConfig) {
- if (auto result = containsValidThresholds(updateConfig.componentLevelThresholds);
- (updatableConfigsFilter & IoOveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS) &&
- !result.ok()) {
- return Error() << "Invalid " << toString(componentType)
- << " component level generic thresholds: " << result.error();
+ const IoOveruseConfiguration& ioOveruseConfig) {
+ auto componentTypeStr = toString(componentType);
+ if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS) {
+ if (auto result = containsValidThresholds(ioOveruseConfig.componentLevelThresholds);
+ !result.ok()) {
+ return Error() << "Invalid " << toString(componentType)
+ << " component level generic thresholds: " << result.error();
+ }
+ if (ioOveruseConfig.componentLevelThresholds.name != componentTypeStr) {
+ return Error() << "Invalid component name "
+ << ioOveruseConfig.componentLevelThresholds.name
+ << " in component level generic thresholds for component "
+ << componentTypeStr;
+ }
}
const auto containsValidSystemWideThresholds = [&]() -> bool {
- if (updateConfig.systemWideThresholds.empty()) {
+ if (ioOveruseConfig.systemWideThresholds.empty()) {
return false;
}
- for (const auto& threshold : updateConfig.systemWideThresholds) {
+ for (const auto& threshold : ioOveruseConfig.systemWideThresholds) {
if (auto result = containsValidThreshold(threshold); !result.ok()) {
return false;
}
}
return true;
};
- if ((updatableConfigsFilter & IoOveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) &&
+ if ((updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) &&
!containsValidSystemWideThresholds()) {
- return Error() << "Invalid system-wide alert threshold provided in "
- << toString(componentType) << " config";
+ return Error() << "Invalid system-wide alert threshold provided in " << componentTypeStr
+ << " config";
+ }
+ return {};
+}
+
+Result<int32_t> getComponentFilter(const ComponentType componentType) {
+ switch (componentType) {
+ case ComponentType::SYSTEM:
+ return kSystemComponentUpdatableConfigs;
+ case ComponentType::VENDOR:
+ return kVendorComponentUpdatableConfigs;
+ case ComponentType::THIRD_PARTY:
+ return kThirdPartyComponentUpdatableConfigs;
+ default:
+ return Error() << "Invalid component type: " << static_cast<int32_t>(componentType);
+ }
+}
+
+Result<void> isValidConfigs(
+ const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) {
+ std::unordered_set<ComponentType> seenComponentTypes;
+ for (const auto& resourceOveruseConfig : resourceOveruseConfigs) {
+ if (seenComponentTypes.count(resourceOveruseConfig.componentType) > 0) {
+ return Error() << "Cannot provide duplicate configs for the same component type "
+ << toString(resourceOveruseConfig.componentType);
+ }
+ const auto filter = getComponentFilter(resourceOveruseConfig.componentType);
+ if (!filter.ok()) {
+ return Error() << filter.error();
+ }
+ seenComponentTypes.insert(resourceOveruseConfig.componentType);
+ if (resourceOveruseConfig.resourceSpecificConfigurations.size() != 1) {
+ return Error() << "Must provide exactly one I/O overuse configuration. Received "
+ << resourceOveruseConfig.resourceSpecificConfigurations.size()
+ << " configurations";
+ }
+ for (const auto& config : resourceOveruseConfig.resourceSpecificConfigurations) {
+ if (config.getTag() != ResourceSpecificConfiguration::ioOveruseConfiguration) {
+ return Error() << "Invalid resource type: " << config.getTag();
+ }
+ const auto& ioOveruseConfig =
+ config.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+ if (auto result = isValidIoOveruseConfiguration(resourceOveruseConfig.componentType,
+ *filter, ioOveruseConfig);
+ !result.ok()) {
+ return Error() << "Invalid config for component "
+ << toString(resourceOveruseConfig.componentType).c_str()
+ << result.error();
+ }
+ }
}
return {};
}
@@ -159,38 +227,36 @@
}
std::string errorMsgs;
for (const auto& packageThreshold : thresholds) {
- std::string packageName = std::string(String8(packageThreshold.name));
- if (packageName.empty()) {
+ if (packageThreshold.name.empty()) {
StringAppendF(&errorMsgs, "\tSkipping per-package threshold without package name\n");
continue;
}
- maybeAppendVendorPackagePrefixes(packageName);
+ maybeAppendVendorPackagePrefixes(packageThreshold.name);
if (auto result = containsValidThresholds(packageThreshold); !result.ok()) {
StringAppendF(&errorMsgs,
"\tSkipping invalid package specific thresholds for package %s: %s\n",
- packageName.c_str(), result.error().message().c_str());
+ packageThreshold.name.c_str(), result.error().message().c_str());
continue;
}
- if (const auto& it = mPerPackageThresholds.find(packageName);
+ if (const auto& it = mPerPackageThresholds.find(packageThreshold.name);
it != mPerPackageThresholds.end()) {
StringAppendF(&errorMsgs, "\tDuplicate threshold received for package '%s'\n",
- packageName.c_str());
+ packageThreshold.name.c_str());
}
- mPerPackageThresholds[packageName] = packageThreshold;
+ mPerPackageThresholds[packageThreshold.name] = packageThreshold;
}
return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
}
Result<void> ComponentSpecificConfig::updateSafeToKillPackages(
- const std::vector<String16>& packages,
+ const std::vector<std::string>& packages,
const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes) {
mSafeToKillPackages.clear();
if (packages.empty()) {
return Error() << "\tNo safe-to-kill packages provided so clearing it\n";
}
std::string errorMsgs;
- for (const auto& packageNameStr16 : packages) {
- std::string packageName = std::string(String8(packageNameStr16));
+ for (const auto& packageName : packages) {
if (packageName.empty()) {
StringAppendF(&errorMsgs, "\tSkipping empty safe-to-kill package name");
continue;
@@ -224,15 +290,15 @@
result.error().message().c_str());
continue;
}
- std::string name = std::string(String8(categoryThreshold.name));
- if (auto category = toApplicationCategoryType(name);
+ if (auto category = toApplicationCategoryType(categoryThreshold.name);
category == ApplicationCategoryType::OTHERS) {
- StringAppendF(&errorMsgs, "\tInvalid application category %s\n", name.c_str());
+ StringAppendF(&errorMsgs, "\tInvalid application category %s\n",
+ categoryThreshold.name.c_str());
} else {
if (const auto& it = mPerCategoryThresholds.find(category);
it != mPerCategoryThresholds.end()) {
StringAppendF(&errorMsgs, "\tDuplicate threshold received for category: '%s'\n",
- name.c_str());
+ categoryThreshold.name.c_str());
}
mPerCategoryThresholds[category] = categoryThreshold;
}
@@ -262,60 +328,90 @@
return errorMsgs.empty() ? Result<void>{} : Error() << errorMsgs;
}
-Result<void> IoOveruseConfigs::update(const ComponentType componentType,
- const IoOveruseConfiguration& updateConfig) {
- const std::string componentTypeStr = toString(componentType);
- if (auto configComponentTypeStr = String8(updateConfig.componentLevelThresholds.name).string();
- configComponentTypeStr != componentTypeStr) {
- return Error(Status::EX_ILLEGAL_ARGUMENT)
- << "Invalid config: Config's component name '" << configComponentTypeStr
- << "' != component name in update request '" << componentTypeStr << "'";
- }
- ComponentSpecificConfig* targetComponentConfig;
- int32_t updatableConfigsFilter = 0;
- switch (componentType) {
- case ComponentType::SYSTEM:
- targetComponentConfig = &mSystemConfig;
- updatableConfigsFilter = kSystemComponentUpdatableConfigs;
- break;
- case ComponentType::VENDOR:
- targetComponentConfig = &mVendorConfig;
- updatableConfigsFilter = kVendorComponentUpdatableConfigs;
- break;
- case ComponentType::THIRD_PARTY:
- targetComponentConfig = &mThirdPartyConfig;
- updatableConfigsFilter = kThirdPartyComponentUpdatableConfigs;
- break;
- default:
- return Error(Status::EX_ILLEGAL_ARGUMENT)
- << "Invalid component type " << componentTypeStr;
- }
- if (auto result =
- isValidIoOveruseConfiguration(componentType, updatableConfigsFilter, updateConfig);
- !result.ok()) {
+Result<void> IoOveruseConfigs::update(
+ const std::vector<ResourceOveruseConfiguration>& resourceOveruseConfigs) {
+ if (auto result = isValidConfigs(resourceOveruseConfigs); !result.ok()) {
return Error(Status::EX_ILLEGAL_ARGUMENT) << result.error();
}
- if ((updatableConfigsFilter & IoOveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) {
- targetComponentConfig->mGeneric = updateConfig.componentLevelThresholds;
+ for (const auto& resourceOveruseConfig : resourceOveruseConfigs) {
+ ComponentSpecificConfig* targetComponentConfig;
+ int32_t updatableConfigsFilter = 0;
+ switch (resourceOveruseConfig.componentType) {
+ case ComponentType::SYSTEM:
+ targetComponentConfig = &mSystemConfig;
+ updatableConfigsFilter = kSystemComponentUpdatableConfigs;
+ break;
+ case ComponentType::VENDOR:
+ targetComponentConfig = &mVendorConfig;
+ updatableConfigsFilter = kVendorComponentUpdatableConfigs;
+ break;
+ case ComponentType::THIRD_PARTY:
+ targetComponentConfig = &mThirdPartyConfig;
+ updatableConfigsFilter = kThirdPartyComponentUpdatableConfigs;
+ break;
+ default:
+ // This case shouldn't execute as it is caught during validation.
+ continue;
+ }
+
+ const std::string componentTypeStr = toString(resourceOveruseConfig.componentType);
+ for (const auto& resourceSpecificConfig :
+ resourceOveruseConfig.resourceSpecificConfigurations) {
+ /*
+ * |resourceSpecificConfig| should contain only ioOveruseConfiguration as it is verified
+ * during validation.
+ */
+ const auto& ioOveruseConfig =
+ resourceSpecificConfig
+ .get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+ if (auto res = update(resourceOveruseConfig, ioOveruseConfig, updatableConfigsFilter,
+ targetComponentConfig);
+ !res.ok()) {
+ ALOGE("Invalid I/O overuse configurations received for %s component:\n%s",
+ componentTypeStr.c_str(), res.error().message().c_str());
+ }
+ }
+ }
+ return {};
+}
+
+Result<void> IoOveruseConfigs::update(
+ const ResourceOveruseConfiguration& resourceOveruseConfiguration,
+ const IoOveruseConfiguration& ioOveruseConfiguration, int32_t updatableConfigsFilter,
+ ComponentSpecificConfig* targetComponentConfig) {
+ if ((updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) {
+ targetComponentConfig->mGeneric = ioOveruseConfiguration.componentLevelThresholds;
}
std::string nonUpdatableConfigMsgs;
- if (updatableConfigsFilter & IoOveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) {
+ if (updatableConfigsFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) {
mVendorPackagePrefixes.clear();
- for (const auto& prefixStr16 : updateConfig.vendorPackagePrefixes) {
- if (auto prefix = std::string(String8(prefixStr16)); !prefix.empty()) {
+ for (const auto& prefix : resourceOveruseConfiguration.vendorPackagePrefixes) {
+ if (!prefix.empty()) {
mVendorPackagePrefixes.insert(prefix);
}
}
- } else if (!updateConfig.vendorPackagePrefixes.empty()) {
+ } else if (!resourceOveruseConfiguration.vendorPackagePrefixes.empty()) {
StringAppendF(&nonUpdatableConfigMsgs, "%svendor packages prefixes",
!nonUpdatableConfigMsgs.empty() ? ", " : "");
}
+ if (updatableConfigsFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) {
+ mPackagesToAppCategories.clear();
+ for (const auto& meta : resourceOveruseConfiguration.packageMetadata) {
+ if (!meta.packageName.empty()) {
+ mPackagesToAppCategories[meta.packageName] = meta.appCategoryType;
+ }
+ }
+ } else if (!resourceOveruseConfiguration.packageMetadata.empty()) {
+ StringAppendF(&nonUpdatableConfigMsgs, "%spackage to application category mappings",
+ !nonUpdatableConfigMsgs.empty() ? ", " : "");
+ }
+
std::string errorMsgs;
const auto maybeAppendVendorPackagePrefixes =
- [& componentType = std::as_const(componentType),
+ [&componentType = std::as_const(resourceOveruseConfiguration.componentType),
&vendorPackagePrefixes = mVendorPackagePrefixes](const std::string& packageName) {
if (componentType != ComponentType::VENDOR) {
return;
@@ -328,46 +424,49 @@
vendorPackagePrefixes.insert(packageName);
};
- if (updatableConfigsFilter & IoOveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) {
- if (auto result =
- targetComponentConfig
- ->updatePerPackageThresholds(updateConfig.packageSpecificThresholds,
- maybeAppendVendorPackagePrefixes);
+ if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) {
+ if (auto result = targetComponentConfig
+ ->updatePerPackageThresholds(ioOveruseConfiguration
+ .packageSpecificThresholds,
+ maybeAppendVendorPackagePrefixes);
!result.ok()) {
StringAppendF(&errorMsgs, "%s", result.error().message().c_str());
}
- } else if (!updateConfig.packageSpecificThresholds.empty()) {
+ } else if (!ioOveruseConfiguration.packageSpecificThresholds.empty()) {
StringAppendF(&nonUpdatableConfigMsgs, "%sper-package thresholds",
!nonUpdatableConfigMsgs.empty() ? ", " : "");
}
- if (updatableConfigsFilter & IoOveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) {
+ if (updatableConfigsFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) {
if (auto result = targetComponentConfig
- ->updateSafeToKillPackages(updateConfig.safeToKillPackages,
+ ->updateSafeToKillPackages(resourceOveruseConfiguration
+ .safeToKillPackages,
maybeAppendVendorPackagePrefixes);
!result.ok()) {
StringAppendF(&errorMsgs, "%s", result.error().message().c_str());
}
- } else if (!updateConfig.safeToKillPackages.empty()) {
+ } else if (!resourceOveruseConfiguration.safeToKillPackages.empty()) {
StringAppendF(&nonUpdatableConfigMsgs, "%ssafe-to-kill list",
!nonUpdatableConfigMsgs.empty() ? ", " : "");
}
- if (updatableConfigsFilter & IoOveruseConfigEnum::PER_CATEGORY_THRESHOLDS) {
- if (auto result = updatePerCategoryThresholds(updateConfig.categorySpecificThresholds);
+ if (updatableConfigsFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) {
+ if (auto result =
+ updatePerCategoryThresholds(ioOveruseConfiguration.categorySpecificThresholds);
!result.ok()) {
StringAppendF(&errorMsgs, "%s", result.error().message().c_str());
}
- } else if (!updateConfig.categorySpecificThresholds.empty()) {
+ } else if (!ioOveruseConfiguration.categorySpecificThresholds.empty()) {
StringAppendF(&nonUpdatableConfigMsgs, "%scategory specific thresholds",
!nonUpdatableConfigMsgs.empty() ? ", " : "");
}
- if (updatableConfigsFilter & IoOveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) {
- if (auto result = updateAlertThresholds(updateConfig.systemWideThresholds); !result.ok()) {
+ if (updatableConfigsFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) {
+ if (auto result = updateAlertThresholds(ioOveruseConfiguration.systemWideThresholds);
+ !result.ok()) {
StringAppendF(&errorMsgs, "%s", result.error().message().c_str());
}
- } else if (!updateConfig.systemWideThresholds.empty()) {
+ } else if (!ioOveruseConfiguration.systemWideThresholds.empty()) {
StringAppendF(&nonUpdatableConfigMsgs, "%ssystem-wide alert thresholds",
!nonUpdatableConfigMsgs.empty() ? ", " : "");
}
@@ -377,17 +476,84 @@
nonUpdatableConfigMsgs.c_str());
}
if (!errorMsgs.empty()) {
- ALOGE("Invalid I/O overuse configs received for %s component:\n%s",
- componentTypeStr.c_str(), errorMsgs.c_str());
+ return Error() << errorMsgs.c_str();
}
return {};
}
+void IoOveruseConfigs::get(std::vector<ResourceOveruseConfiguration>* resourceOveruseConfigs) {
+ auto systemConfig = get(mSystemConfig, kSystemComponentUpdatableConfigs);
+ if (systemConfig.has_value()) {
+ systemConfig->componentType = ComponentType::SYSTEM;
+ resourceOveruseConfigs->emplace_back(std::move(*systemConfig));
+ }
+
+ auto vendorConfig = get(mVendorConfig, kVendorComponentUpdatableConfigs);
+ if (vendorConfig.has_value()) {
+ vendorConfig->componentType = ComponentType::VENDOR;
+ resourceOveruseConfigs->emplace_back(std::move(*vendorConfig));
+ }
+
+ auto thirdPartyConfig = get(mThirdPartyConfig, kThirdPartyComponentUpdatableConfigs);
+ if (thirdPartyConfig.has_value()) {
+ thirdPartyConfig->componentType = ComponentType::THIRD_PARTY;
+ resourceOveruseConfigs->emplace_back(std::move(*thirdPartyConfig));
+ }
+}
+
+std::optional<ResourceOveruseConfiguration> IoOveruseConfigs::get(
+ const ComponentSpecificConfig& componentSpecificConfig, const int32_t componentFilter) {
+ if (componentSpecificConfig.mGeneric.name == kDefaultThresholdName) {
+ return {};
+ }
+ ResourceOveruseConfiguration resourceOveruseConfiguration;
+ IoOveruseConfiguration ioOveruseConfiguration;
+ if ((componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_GENERIC_THRESHOLDS)) {
+ ioOveruseConfiguration.componentLevelThresholds = componentSpecificConfig.mGeneric;
+ }
+ if (componentFilter & OveruseConfigEnum::VENDOR_PACKAGE_PREFIXES) {
+ resourceOveruseConfiguration.vendorPackagePrefixes = toStringVector(mVendorPackagePrefixes);
+ }
+ if (componentFilter & OveruseConfigEnum::PACKAGE_APP_CATEGORY_MAPPINGS) {
+ for (const auto& [packageName, appCategoryType] : mPackagesToAppCategories) {
+ PackageMetadata meta;
+ meta.packageName = packageName;
+ meta.appCategoryType = appCategoryType;
+ resourceOveruseConfiguration.packageMetadata.push_back(meta);
+ }
+ }
+ if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_PER_PACKAGE_THRESHOLDS) {
+ for (const auto& [packageName, threshold] : componentSpecificConfig.mPerPackageThresholds) {
+ ioOveruseConfiguration.packageSpecificThresholds.push_back(threshold);
+ }
+ }
+ if (componentFilter & OveruseConfigEnum::COMPONENT_SPECIFIC_SAFE_TO_KILL_PACKAGES) {
+ resourceOveruseConfiguration.safeToKillPackages =
+ toStringVector(componentSpecificConfig.mSafeToKillPackages);
+ }
+ if (componentFilter & OveruseConfigEnum::PER_CATEGORY_THRESHOLDS) {
+ for (const auto& [category, threshold] : mPerCategoryThresholds) {
+ ioOveruseConfiguration.categorySpecificThresholds.push_back(threshold);
+ }
+ }
+ if (componentFilter & OveruseConfigEnum::SYSTEM_WIDE_ALERT_THRESHOLDS) {
+ for (const auto& threshold : mAlertThresholds) {
+ ioOveruseConfiguration.systemWideThresholds.push_back(threshold);
+ }
+ }
+ ResourceSpecificConfiguration resourceSpecificConfig;
+ resourceSpecificConfig.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(
+ ioOveruseConfiguration);
+ resourceOveruseConfiguration.resourceSpecificConfigurations.emplace_back(
+ std::move(resourceSpecificConfig));
+ return resourceOveruseConfiguration;
+}
+
PerStateBytes IoOveruseConfigs::fetchThreshold(const PackageInfo& packageInfo) const {
- const std::string packageName = std::string(String8(packageInfo.packageIdentifier.name));
switch (packageInfo.componentType) {
case ComponentType::SYSTEM:
- if (const auto it = mSystemConfig.mPerPackageThresholds.find(packageName);
+ if (const auto it = mSystemConfig.mPerPackageThresholds.find(
+ packageInfo.packageIdentifier.name);
it != mSystemConfig.mPerPackageThresholds.end()) {
return it->second.perStateWriteBytes;
}
@@ -397,7 +563,8 @@
}
return mSystemConfig.mGeneric.perStateWriteBytes;
case ComponentType::VENDOR:
- if (const auto it = mVendorConfig.mPerPackageThresholds.find(packageName);
+ if (const auto it = mVendorConfig.mPerPackageThresholds.find(
+ packageInfo.packageIdentifier.name);
it != mVendorConfig.mPerPackageThresholds.end()) {
return it->second.perStateWriteBytes;
}
@@ -424,13 +591,12 @@
// Native packages can't be disabled so don't kill them on I/O overuse.
return false;
}
- const std::string packageName = std::string(String8(packageInfo.packageIdentifier.name));
switch (packageInfo.componentType) {
case ComponentType::SYSTEM:
- return mSystemConfig.mSafeToKillPackages.find(packageName) !=
+ return mSystemConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
mSystemConfig.mSafeToKillPackages.end();
case ComponentType::VENDOR:
- return mVendorConfig.mSafeToKillPackages.find(packageName) !=
+ return mVendorConfig.mSafeToKillPackages.find(packageInfo.packageIdentifier.name) !=
mVendorConfig.mSafeToKillPackages.end();
default:
return true;
diff --git a/cpp/watchdog/server/src/IoOveruseConfigs.h b/cpp/watchdog/server/src/IoOveruseConfigs.h
index 84577f1..cd80a95 100644
--- a/cpp/watchdog/server/src/IoOveruseConfigs.h
+++ b/cpp/watchdog/server/src/IoOveruseConfigs.h
@@ -23,10 +23,9 @@
#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
#include <android/automotive/watchdog/internal/ComponentType.h>
#include <android/automotive/watchdog/internal/IoOveruseAlertThreshold.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
#include <android/automotive/watchdog/internal/PackageInfo.h>
#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
-#include <utils/String16.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
#include <optional>
#include <string>
@@ -37,11 +36,12 @@
namespace android {
namespace automotive {
namespace watchdog {
+constexpr const char* kDefaultThresholdName = "default";
inline const android::automotive::watchdog::internal::PerStateIoOveruseThreshold
defaultThreshold() {
android::automotive::watchdog::internal::PerStateIoOveruseThreshold threshold;
- threshold.name = android::String16("default");
+ threshold.name = kDefaultThresholdName;
threshold.perStateWriteBytes.foregroundBytes = std::numeric_limits<uint64_t>::max();
threshold.perStateWriteBytes.backgroundBytes = std::numeric_limits<uint64_t>::max();
threshold.perStateWriteBytes.garageModeBytes = std::numeric_limits<uint64_t>::max();
@@ -53,10 +53,14 @@
*/
class IIoOveruseConfigs : public android::RefBase {
public:
- // Overwrites the existing configuration for the given |componentType|.
- virtual android::base::Result<void> update(
- const android::automotive::watchdog::internal::ComponentType componentType,
- const android::automotive::watchdog::internal::IoOveruseConfiguration& config) = 0;
+ // Overwrites the existing configurations.
+ virtual android::base::Result<void>
+ update(const std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+ configs) = 0;
+ // Returns the existing configurations.
+ virtual void get(
+ std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+ resourceOveruseConfigs) = 0;
/*
* Returns the list of vendor package prefixes. Any pre-installed package matching one of these
@@ -64,6 +68,13 @@
*/
virtual const std::unordered_set<std::string>& vendorPackagePrefixes() = 0;
+ /*
+ * Returns the package names to application category mappings.
+ */
+ virtual const std::unordered_map<
+ std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+ packagesToAppCategories() = 0;
+
// Fetches the I/O overuse thresholds for the given package.
virtual PerStateBytes fetchThreshold(
const android::automotive::watchdog::internal::PackageInfo& packageInfo) const = 0;
@@ -118,7 +129,7 @@
* Updates |mSafeToKillPackages|.
*/
android::base::Result<void> updateSafeToKillPackages(
- const std::vector<android::String16>& packages,
+ const std::vector<std::string>& packages,
const std::function<void(const std::string&)>& maybeAppendVendorPackagePrefixes);
/*
@@ -155,10 +166,12 @@
mAlertThresholds.clear();
}
- // Overwrites the existing configuration for the given |componentType|.
- android::base::Result<void> update(
- const android::automotive::watchdog::internal::ComponentType componentType,
- const android::automotive::watchdog::internal::IoOveruseConfiguration& config);
+ android::base::Result<void>
+ update(const std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+ configs);
+
+ void get(std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+ resourceOveruseConfigs);
PerStateBytes fetchThreshold(
const android::automotive::watchdog::internal::PackageInfo& packageInfo) const;
@@ -172,13 +185,33 @@
return mVendorPackagePrefixes;
}
+ const std::unordered_map<std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>&
+ packagesToAppCategories() {
+ return mPackagesToAppCategories;
+ }
+
private:
+ android::base::Result<void> update(
+ const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+ resourceOveruseConfiguration,
+ const android::automotive::watchdog::internal::IoOveruseConfiguration&
+ ioOveruseConfiguration,
+ int32_t updatableConfigsFilter, ComponentSpecificConfig* targetComponentConfig);
+
+ std::optional<android::automotive::watchdog::internal::ResourceOveruseConfiguration> get(
+ const ComponentSpecificConfig& componentSpecificConfig, const int32_t componentFilter);
+
// System component specific configuration.
ComponentSpecificConfig mSystemConfig;
// Vendor component specific configuration.
ComponentSpecificConfig mVendorConfig;
// Third-party component specific configuration.
ComponentSpecificConfig mThirdPartyConfig;
+ // Package name to application category mappings.
+ std::unordered_map<std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>
+ mPackagesToAppCategories;
// I/O overuse thresholds per category.
std::unordered_map<android::automotive::watchdog::internal::ApplicationCategoryType,
android::automotive::watchdog::internal::PerStateIoOveruseThreshold>
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.cpp b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
index 8b25a83..080b284 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.cpp
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "carwatchdogd"
+#define DEBUG false // STOPSHIP if true.
#include "IoOveruseMonitor.h"
@@ -27,6 +28,8 @@
#include <binder/Status.h>
#include <cutils/multiuser.h>
+#include <limits>
+
namespace android {
namespace automotive {
namespace watchdog {
@@ -38,18 +41,23 @@
using ::android::automotive::watchdog::internal::PackageInfo;
using ::android::automotive::watchdog::internal::PackageIoOveruseStats;
using ::android::automotive::watchdog::internal::PackageResourceOveruseAction;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
using ::android::automotive::watchdog::internal::UidType;
using ::android::base::Error;
using ::android::base::Result;
using ::android::binder::Status;
+// Minimum written bytes to sync the stats with the Watchdog service.
+constexpr uint64_t kMinSyncWrittenBytes = 100 * 1024;
+// Minimum percentage of threshold to warn killable applications.
constexpr double kDefaultIoOveruseWarnPercentage = 80;
+// Maximum numer of system-wide stats (from periodic monitoring) to cache.
constexpr size_t kMaxPeriodicMonitorBufferSize = 1000;
namespace {
std::string uniquePackageIdStr(const PackageIdentifier& id) {
- return StringPrintf("%s:%" PRId32, String8(id.name).c_str(), multiuser_get_user_id(id.uid));
+ return StringPrintf("%s:%" PRId32, id.name.c_str(), multiuser_get_user_id(id.uid));
}
PerStateBytes diff(const PerStateBytes& lhs, const PerStateBytes& rhs) {
@@ -75,6 +83,15 @@
return std::make_tuple(startTime, currentEpochSeconds - startTime);
}
+uint64_t totalPerStateBytes(PerStateBytes perStateBytes) {
+ const auto sum = [](const uint64_t& l, const uint64_t& r) -> uint64_t {
+ return std::numeric_limits<uint64_t>::max() - l > r ? (l + r)
+ : std::numeric_limits<uint64_t>::max();
+ };
+ return sum(perStateBytes.foregroundBytes,
+ sum(perStateBytes.backgroundBytes, perStateBytes.garageModeBytes));
+}
+
} // namespace
std::tuple<int64_t, int64_t> calculateStartAndDuration(const time_t& currentTime) {
@@ -83,6 +100,19 @@
return calculateStartAndDuration(currentGmt);
}
+IoOveruseMonitor::IoOveruseMonitor(
+ const android::sp<IWatchdogServiceHelperInterface>& watchdogServiceHelper) :
+ mMinSyncWrittenBytes(kMinSyncWrittenBytes),
+ mWatchdogServiceHelper(watchdogServiceHelper),
+ mSystemWideWrittenBytes({}),
+ mPeriodicMonitorBufferSize(0),
+ mLastSystemWideIoMonitorTime(0),
+ mUserPackageDailyIoUsageById({}),
+ mIoOveruseWarnPercentage(0),
+ mLastUserPackageIoMonitorTime(0),
+ mOveruseListenersByUid({}),
+ mBinderDeathRecipient(new BinderDeathRecipient(this)) {}
+
Result<void> IoOveruseMonitor::init() {
std::unique_lock writeLock(mRwMutex);
if (isInitializedLocked()) {
@@ -99,7 +129,7 @@
mIoOveruseWarnPercentage = static_cast<double>(
sysprop::ioOveruseWarnPercentage().value_or(kDefaultIoOveruseWarnPercentage));
/*
- * TODO(b/167240592): Read the latest I/O overuse config.
+ * TODO(b/185287136): Read the latest I/O overuse config.
* The latest I/O overuse config is read in this order:
* 1. From /data partition as this contains the latest config and any updates received from OEM
* and system applications.
@@ -108,9 +138,13 @@
*/
mIoOveruseConfigs = new IoOveruseConfigs();
- // TODO(b/167240592): Read the vendor package prefixes from disk before the below call.
+ // TODO(b/185287136): Read the vendor package prefixes from disk before the below call.
mPackageInfoResolver = PackageInfoResolver::getInstance();
- mPackageInfoResolver->setVendorPackagePrefixes(mIoOveruseConfigs->vendorPackagePrefixes());
+ mPackageInfoResolver->setPackageConfigurations(mIoOveruseConfigs->vendorPackagePrefixes(),
+ mIoOveruseConfigs->packagesToAppCategories());
+ if (DEBUG) {
+ ALOGD("Initialized %s data processor", name().c_str());
+ }
return {};
}
@@ -127,6 +161,9 @@
}
mBinderDeathRecipient.clear();
mOveruseListenersByUid.clear();
+ if (DEBUG) {
+ ALOGD("Terminated %s data processor", name().c_str());
+ }
return;
}
@@ -146,7 +183,7 @@
/*
* Date changed so reset the daily I/O usage cache.
*
- * TODO(b/170741935): Ping CarWatchdogService on date change so it can re-enable the daily
+ * TODO(b/185287136): Ping CarWatchdogService on date change so it can re-enable the daily
* disabled packages. Also sync prev day's stats with CarWatchdogService.
*/
mUserPackageDailyIoUsageById.clear();
@@ -154,14 +191,26 @@
mLastUserPackageIoMonitorTime = time;
const auto [startTime, durationInSeconds] = calculateStartAndDuration(curGmt);
- const auto perUidIoUsage = uidIoStats.promote()->deltaStats();
+ auto perUidIoUsage = uidIoStats.promote()->deltaStats();
/*
- * TODO(b/167240592): Maybe move the packageInfo fetching logic into UidIoStats module.
+ * TODO(b/185849350): Maybe move the packageInfo fetching logic into UidIoStats module.
* This will also help avoid fetching package names in IoPerfCollection module.
*/
std::vector<uid_t> seenUids;
- for (const auto& [uid, uidIoStats] : perUidIoUsage) {
- seenUids.push_back(uid);
+ for (auto it = perUidIoUsage.begin(); it != perUidIoUsage.end();) {
+ /*
+ * UidIoStats::deltaStats returns entries with zero write bytes because other metrics
+ * in these entries are non-zero.
+ */
+ if (it->second.ios.sumWriteBytes() == 0) {
+ it = perUidIoUsage.erase(it);
+ continue;
+ }
+ seenUids.push_back(it->first);
+ ++it;
+ }
+ if (perUidIoUsage.empty()) {
+ return {};
}
const auto packageInfosByUid = mPackageInfoResolver->getPackageInfosForUids(seenUids);
std::unordered_map<uid_t, IoOveruseStats> overusingNativeStats;
@@ -171,7 +220,7 @@
continue;
}
/*
- * TODO(b/167240592): Derive the garage mode status from the collection flag, which will
+ * TODO(b/185498771): Derive the garage mode status from the collection flag, which will
* be added to the |onPeriodicCollection| API.
*/
UserPackageIoUsage curUsage(packageInfo->second, uidIoStats.ios,
@@ -202,6 +251,16 @@
mIoOveruseConfigs->isSafeToKill(dailyIoUsage->packageInfo);
const auto& remainingWriteBytes = stats.ioOveruseStats.remainingWriteBytes;
+ const auto exceedsWarnThreshold = [&](double remaining, double threshold) {
+ if (threshold == 0) {
+ return true;
+ }
+ double usedPercent = (100 - (remaining / threshold) * 100);
+ return usedPercent > mIoOveruseWarnPercentage;
+ };
+ bool shouldSyncWatchdogService =
+ (totalPerStateBytes(dailyIoUsage->writtenBytes) -
+ dailyIoUsage->lastSyncedWrittenBytes) >= mMinSyncWrittenBytes;
if (remainingWriteBytes.foregroundBytes == 0 || remainingWriteBytes.backgroundBytes == 0 ||
remainingWriteBytes.garageModeBytes == 0) {
stats.ioOveruseStats.totalOveruses = ++dailyIoUsage->totalOveruses;
@@ -219,45 +278,44 @@
if (dailyIoUsage->packageInfo.uidType == UidType::NATIVE) {
overusingNativeStats[uid] = stats.ioOveruseStats;
}
- mLatestIoOveruseStats.emplace_back(std::move(stats));
- continue;
- }
- if (dailyIoUsage->packageInfo.uidType == UidType::NATIVE ||
- !stats.ioOveruseStats.killableOnOveruse || dailyIoUsage->isPackageWarned) {
+ shouldSyncWatchdogService = true;
+ } else if (dailyIoUsage->packageInfo.uidType != UidType::NATIVE &&
+ stats.ioOveruseStats.killableOnOveruse && !dailyIoUsage->isPackageWarned &&
+ (exceedsWarnThreshold(remainingWriteBytes.foregroundBytes,
+ threshold.foregroundBytes) ||
+ exceedsWarnThreshold(remainingWriteBytes.backgroundBytes,
+ threshold.backgroundBytes) ||
+ exceedsWarnThreshold(remainingWriteBytes.garageModeBytes,
+ threshold.garageModeBytes))) {
/*
* No need to warn native services or applications that won't be killed on I/O overuse
* as they will be sent a notification when they exceed their daily threshold.
*/
- mLatestIoOveruseStats.emplace_back(std::move(stats));
- continue;
- }
- const auto exceedsWarnThreshold = [&](double remaining, double threshold) {
- if (threshold == 0) {
- return true;
- }
- double usedPercent = (100 - (remaining / threshold) * 100);
- return usedPercent > mIoOveruseWarnPercentage;
- };
- if (exceedsWarnThreshold(remainingWriteBytes.foregroundBytes, threshold.foregroundBytes) ||
- exceedsWarnThreshold(remainingWriteBytes.backgroundBytes, threshold.backgroundBytes) ||
- exceedsWarnThreshold(remainingWriteBytes.garageModeBytes, threshold.garageModeBytes)) {
stats.shouldNotify = true;
// Avoid duplicate warning before the daily threshold exceeded notification is sent.
dailyIoUsage->isPackageWarned = true;
+ shouldSyncWatchdogService = true;
}
- mLatestIoOveruseStats.emplace_back(std::move(stats));
+ if (shouldSyncWatchdogService) {
+ dailyIoUsage->lastSyncedWrittenBytes = totalPerStateBytes(dailyIoUsage->writtenBytes);
+ mLatestIoOveruseStats.emplace_back(std::move(stats));
+ }
}
-
if (!overusingNativeStats.empty()) {
notifyNativePackagesLocked(overusingNativeStats);
}
-
+ if (mLatestIoOveruseStats.empty()) {
+ return {};
+ }
if (const auto status = mWatchdogServiceHelper->latestIoOveruseStats(mLatestIoOveruseStats);
!status.isOk()) {
// Don't clear the cache as it can be pushed again on the next collection.
ALOGW("Failed to push the latest I/O overuse stats to watchdog service");
} else {
mLatestIoOveruseStats.clear();
+ if (DEBUG) {
+ ALOGD("Pushed latest I/O overuse stats to watchdog service");
+ }
}
return {};
@@ -277,6 +335,8 @@
if (procDiskStats == nullptr) {
return Error() << "Proc disk stats collector must not be null";
}
+
+ std::unique_lock writeLock(mRwMutex);
if (mLastSystemWideIoMonitorTime == 0) {
/*
* Do not record the first disk stats as it reflects the aggregated disks stats since the
@@ -324,12 +384,12 @@
}
Result<void> IoOveruseMonitor::onShutdownPrepareComplete() {
- // TODO(b/167240592): Flush in-memory stats to disk.
+ // TODO(b/185287136): Flush in-memory stats to disk.
return {};
}
Result<void> IoOveruseMonitor::onDump([[maybe_unused]] int fd) {
- // TODO(b/167240592): Dump the list of killed/disabled packages. Dump the list of packages that
+ // TODO(b/183436216): Dump the list of killed/disabled packages. Dump the list of packages that
// exceed xx% of their threshold.
return {};
}
@@ -347,21 +407,37 @@
stats.set<ResourceOveruseStats::ioOveruseStats>(ioOveruseStats);
listener->onOveruse(stats);
}
- // TODO(b/167240592): Upload I/O overuse metrics for native packages.
+ if (DEBUG) {
+ ALOGD("Notified native packages on I/O overuse");
+ }
+ // TODO(b/184310189): Upload I/O overuse metrics for native packages.
}
-Result<void> IoOveruseMonitor::updateIoOveruseConfiguration(ComponentType type,
- const IoOveruseConfiguration& config) {
+Result<void> IoOveruseMonitor::updateResourceOveruseConfigurations(
+ const std::vector<ResourceOveruseConfiguration>& configs) {
std::unique_lock writeLock(mRwMutex);
if (!isInitializedLocked()) {
return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
}
- return mIoOveruseConfigs->update(type, config);
+ return mIoOveruseConfigs->update(configs);
+}
+
+Result<void> IoOveruseMonitor::getResourceOveruseConfigurations(
+ std::vector<ResourceOveruseConfiguration>* configs) {
+ std::shared_lock readLock(mRwMutex);
+ if (!isInitializedLocked()) {
+ return Error(Status::EX_ILLEGAL_STATE) << name() << " is not initialized";
+ }
+ mIoOveruseConfigs->get(configs);
+ return {};
}
Result<void> IoOveruseMonitor::actionTakenOnIoOveruse(
[[maybe_unused]] const std::vector<PackageResourceOveruseAction>& actions) {
- // TODO(b/167240592): Upload metrics.
+ // TODO(b/184310189): Upload metrics.
+ if (DEBUG) {
+ ALOGD("Recorded action taken on I/O overuse");
+ }
return {};
}
@@ -381,6 +457,9 @@
<< "(pid " << callingPid << ", uid: " << callingUid << ") is dead";
}
mOveruseListenersByUid[callingUid] = listener;
+ if (DEBUG) {
+ ALOGD("Added I/O overuse listener for uid: %d", callingUid);
+ }
return {};
}
@@ -396,11 +475,14 @@
!findListenerAndProcessLocked(binder, processor)) {
return Error(Status::EX_ILLEGAL_ARGUMENT) << "Listener is not previously registered";
}
+ if (DEBUG) {
+ ALOGD("Removed I/O overuse listener for uid: %d", IPCThreadState::self()->getCallingUid());
+ }
return {};
}
Result<void> IoOveruseMonitor::getIoOveruseStats(IoOveruseStats* ioOveruseStats) {
- if (std::shared_lock readLock(mRwMutex); !isInitializedLocked()) {
+ if (!isInitialized()) {
return Error(Status::EX_ILLEGAL_STATE) << "I/O overuse monitor is not initialized";
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -433,6 +515,9 @@
calculateStartAndDuration(mLastUserPackageIoMonitorTime);
ioOveruseStats->startTime = startTime;
ioOveruseStats->durationInSeconds = durationInSeconds;
+ if (DEBUG) {
+ ALOGD("Returning I/O overuse listener for uid: %d", callingUid);
+ }
return {};
}
diff --git a/cpp/watchdog/server/src/IoOveruseMonitor.h b/cpp/watchdog/server/src/IoOveruseMonitor.h
index e96f749..7040353 100644
--- a/cpp/watchdog/server/src/IoOveruseMonitor.h
+++ b/cpp/watchdog/server/src/IoOveruseMonitor.h
@@ -66,10 +66,17 @@
*/
class IIoOveruseMonitor : virtual public IDataProcessorInterface {
public:
+ // Returns whether or not the monitor is initialized.
+ virtual bool isInitialized() = 0;
+
// Below API is from internal/ICarWatchdog.aidl. Please refer to the AIDL for description.
- virtual android::base::Result<void> updateIoOveruseConfiguration(
- android::automotive::watchdog::internal::ComponentType type,
- const android::automotive::watchdog::internal::IoOveruseConfiguration& config) = 0;
+ virtual android::base::Result<void> updateResourceOveruseConfigurations(
+ const std::vector<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+ configs) = 0;
+ virtual android::base::Result<void> getResourceOveruseConfigurations(
+ std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+ configs) = 0;
virtual android::base::Result<void> actionTakenOnIoOveruse(
const std::vector<
android::automotive::watchdog::internal::PackageResourceOveruseAction>&
@@ -88,19 +95,15 @@
class IoOveruseMonitor final : public IIoOveruseMonitor {
public:
explicit IoOveruseMonitor(
- const android::sp<IWatchdogServiceHelperInterface>& watchdogServiceHelper) :
- mWatchdogServiceHelper(watchdogServiceHelper),
- mSystemWideWrittenBytes({}),
- mPeriodicMonitorBufferSize(0),
- mLastSystemWideIoMonitorTime(0),
- mUserPackageDailyIoUsageById({}),
- mIoOveruseWarnPercentage(0),
- mLastUserPackageIoMonitorTime(0),
- mOveruseListenersByUid({}),
- mBinderDeathRecipient(new BinderDeathRecipient(this)) {}
+ const android::sp<IWatchdogServiceHelperInterface>& watchdogServiceHelper);
~IoOveruseMonitor() { terminate(); }
+ bool isInitialized() {
+ std::shared_lock readLock(mRwMutex);
+ return isInitializedLocked();
+ }
+
// Below methods implement IDataProcessorInterface.
std::string name() { return "IoOveruseMonitor"; }
friend std::ostream& operator<<(std::ostream& os, const IoOveruseMonitor& monitor);
@@ -112,7 +115,7 @@
return {};
}
- // TODO(b/167240592): Forward WatchdogBinderMediator's notifySystemStateChange call to
+ // TODO(b/185498771): Forward WatchdogBinderMediator's notifySystemStateChange call to
// WatchdogPerfService. On POWER_CYCLE_SHUTDOWN_PREPARE, switch to garage mode collection
// and pass collection flag as a param in this API to indicate garage mode collection.
android::base::Result<void> onPeriodicCollection(time_t time,
@@ -129,7 +132,7 @@
time_t time, const android::wp<IProcDiskStatsInterface>& procDiskStats,
const std::function<void()>& alertHandler);
- // TODO(b/167240592): Forward WatchdogBinderMediator's notifySystemStateChange call to
+ // TODO(b/185498771): Forward WatchdogBinderMediator's notifySystemStateChange call to
// WatchdogProcessService. On POWER_CYCLE_SHUTDOWN_PREPARE_COMPLETE, call this method via
// the IDataProcessorInterface. onShutdownPrepareComplete, IoOveruseMonitor will flush
// in-memory stats to disk.
@@ -143,9 +146,14 @@
}
// Below methods implement AIDL interfaces.
- android::base::Result<void> updateIoOveruseConfiguration(
- android::automotive::watchdog::internal::ComponentType type,
- const android::automotive::watchdog::internal::IoOveruseConfiguration& config);
+ android::base::Result<void> updateResourceOveruseConfigurations(
+ const std::vector<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>&
+ configs);
+
+ android::base::Result<void> getResourceOveruseConfigurations(
+ std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+ configs);
android::base::Result<void> actionTakenOnIoOveruse(
const std::vector<
@@ -178,6 +186,7 @@
PerStateBytes forgivenWriteBytes = {};
int totalOveruses = 0;
bool isPackageWarned = false;
+ uint64_t lastSyncedWrittenBytes = 0;
UserPackageIoUsage& operator+=(const UserPackageIoUsage& r);
@@ -208,14 +217,15 @@
using Processor = std::function<void(ListenersByUidMap&, ListenersByUidMap::const_iterator)>;
bool findListenerAndProcessLocked(const sp<IBinder>& binder, const Processor& processor);
- // Local IPackageInfoResolverInterface instance. Useful to mock in tests.
- sp<IPackageInfoResolverInterface> mPackageInfoResolver;
+ // Local IPackageInfoResolver instance. Useful to mock in tests.
+ sp<IPackageInfoResolver> mPackageInfoResolver;
+ // Minimum written bytes to sync the stats with the Watchdog service.
+ double mMinSyncWrittenBytes;
+ android::sp<IWatchdogServiceHelperInterface> mWatchdogServiceHelper;
// Makes sure only one collection is running at any given time.
mutable std::shared_mutex mRwMutex;
- android::sp<IWatchdogServiceHelperInterface> mWatchdogServiceHelper GUARDED_BY(mRwMutex);
-
// Summary of configs available for all the components and system-wide overuse alert thresholds.
sp<IIoOveruseConfigs> mIoOveruseConfigs GUARDED_BY(mRwMutex);
diff --git a/cpp/watchdog/server/src/IoPerfCollection.cpp b/cpp/watchdog/server/src/IoPerfCollection.cpp
index 059059a..22dc45f 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.cpp
+++ b/cpp/watchdog/server/src/IoPerfCollection.cpp
@@ -421,9 +421,6 @@
for (const auto& uIt : usages) {
const UidIoUsage& curUsage = uIt.second;
- if (curUsage.ios.isZero()) {
- continue;
- }
uids.push_back(curUsage.uid);
uidIoPerfData->total[READ_BYTES][FOREGROUND] +=
curUsage.ios.metrics[READ_BYTES][FOREGROUND];
diff --git a/cpp/watchdog/server/src/IoPerfCollection.h b/cpp/watchdog/server/src/IoPerfCollection.h
index c8a9627..e86320f 100644
--- a/cpp/watchdog/server/src/IoPerfCollection.h
+++ b/cpp/watchdog/server/src/IoPerfCollection.h
@@ -195,8 +195,8 @@
// Top N per-process stats per subcategory.
int mTopNStatsPerSubcategory;
- // Local IPackageInfoResolverInterface instance. Useful to mock in tests.
- sp<IPackageInfoResolverInterface> mPackageInfoResolver;
+ // Local IPackageInfoResolver instance. Useful to mock in tests.
+ sp<IPackageInfoResolver> mPackageInfoResolver;
// Makes sure only one collection is running at any given time.
Mutex mMutex;
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.cpp b/cpp/watchdog/server/src/PackageInfoResolver.cpp
index 2e22909..1a4346a 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.cpp
+++ b/cpp/watchdog/server/src/PackageInfoResolver.cpp
@@ -23,10 +23,10 @@
#include <android/automotive/watchdog/internal/ComponentType.h>
#include <android/automotive/watchdog/internal/UidType.h>
#include <cutils/android_filesystem_config.h>
-#include <utils/String16.h>
#include <inttypes.h>
+#include <iterator>
#include <string_view>
namespace android {
@@ -35,7 +35,6 @@
using ::android::IBinder;
using ::android::sp;
-using ::android::String16;
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::PackageInfo;
@@ -46,10 +45,13 @@
using ::android::binder::Status;
using GetpwuidFunction = std::function<struct passwd*(uid_t)>;
+using PackageToAppCategoryMap =
+ std::unordered_map<std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>;
namespace {
-constexpr const char16_t* kSharedPackagePrefix = u"shared:";
+constexpr const char* kSharedPackagePrefix = "shared:";
ComponentType getComponentTypeForNativeUid(uid_t uid, std::string_view packageName,
const std::vector<std::string>& vendorPackagePrefixes) {
@@ -79,15 +81,11 @@
return Error() << "Failed to fetch package name";
}
const char* packageName = usrpwd->pw_name;
- packageInfo.packageIdentifier.name = String16(packageName);
+ packageInfo.packageIdentifier.name = packageName;
packageInfo.packageIdentifier.uid = uid;
packageInfo.uidType = UidType::NATIVE;
packageInfo.componentType =
getComponentTypeForNativeUid(uid, packageName, vendorPackagePrefixes);
- /**
- * TODO(b/167240592): Identify application category type using the package names. Vendor
- * should define the mappings from package name to the application category type.
- */
packageInfo.appCategoryType = ApplicationCategoryType::OTHERS;
packageInfo.sharedUidPackages = {};
@@ -99,7 +97,7 @@
sp<PackageInfoResolver> PackageInfoResolver::sInstance = nullptr;
GetpwuidFunction PackageInfoResolver::sGetpwuidHandler = &getpwuid;
-sp<IPackageInfoResolverInterface> PackageInfoResolver::getInstance() {
+sp<IPackageInfoResolver> PackageInfoResolver::getInstance() {
if (sInstance == nullptr) {
sInstance = new PackageInfoResolver();
}
@@ -123,13 +121,15 @@
return {};
}
-void PackageInfoResolver::setVendorPackagePrefixes(
- const std::unordered_set<std::string>& prefixes) {
+void PackageInfoResolver::setPackageConfigurations(
+ const std::unordered_set<std::string>& vendorPackagePrefixes,
+ const PackageToAppCategoryMap& packagesToAppCategories) {
std::unique_lock writeLock(mRWMutex);
mVendorPackagePrefixes.clear();
- for (const auto& prefix : prefixes) {
- mVendorPackagePrefixes.push_back(prefix);
- }
+ std::copy(vendorPackagePrefixes.begin(), vendorPackagePrefixes.end(),
+ std::back_inserter(mVendorPackagePrefixes));
+ mPackagesToAppCategories = packagesToAppCategories;
+ // Clear the package info cache as the package configurations have changed.
mUidToPackageInfoMapping.clear();
}
@@ -151,7 +151,7 @@
continue;
}
mUidToPackageInfoMapping[uid] = *result;
- if (result->packageIdentifier.name.startsWith(kSharedPackagePrefix)) {
+ if (StartsWith(result->packageIdentifier.name, kSharedPackagePrefix)) {
// When the UID is shared, poll car watchdog service to fetch the shared packages info.
missingUids.emplace_back(static_cast<int32_t>(uid));
}
@@ -174,11 +174,16 @@
status.exceptionMessage().c_str());
return;
}
- for (const auto& packageInfo : packageInfos) {
- if (packageInfo.packageIdentifier.name.size() == 0) {
+ for (auto& packageInfo : packageInfos) {
+ const auto& id = packageInfo.packageIdentifier;
+ if (id.name.empty()) {
continue;
}
- mUidToPackageInfoMapping[packageInfo.packageIdentifier.uid] = packageInfo;
+ if (const auto it = mPackagesToAppCategories.find(id.name);
+ packageInfo.uidType == UidType::APPLICATION && it != mPackagesToAppCategories.end()) {
+ packageInfo.appCategoryType = it->second;
+ }
+ mUidToPackageInfoMapping[id.uid] = packageInfo;
}
}
@@ -193,8 +198,8 @@
std::shared_lock readLock(mRWMutex);
for (const auto& uid : uids) {
if (mUidToPackageInfoMapping.find(uid) != mUidToPackageInfoMapping.end()) {
- uidToPackageNameMapping[uid] = std::string(
- String8(mUidToPackageInfoMapping.at(uid).packageIdentifier.name));
+ uidToPackageNameMapping[uid] =
+ mUidToPackageInfoMapping.at(uid).packageIdentifier.name;
}
}
}
diff --git a/cpp/watchdog/server/src/PackageInfoResolver.h b/cpp/watchdog/server/src/PackageInfoResolver.h
index c0fc139..e13f47b 100644
--- a/cpp/watchdog/server/src/PackageInfoResolver.h
+++ b/cpp/watchdog/server/src/PackageInfoResolver.h
@@ -20,6 +20,7 @@
#include "WatchdogServiceHelper.h"
#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
#include <android/automotive/watchdog/internal/PackageInfo.h>
#include <binder/IBinder.h>
#include <gtest/gtest_prod.h>
@@ -49,7 +50,7 @@
} // namespace internal
-class IPackageInfoResolverInterface : public android::RefBase {
+class IPackageInfoResolver : public android::RefBase {
public:
virtual std::unordered_map<uid_t, std::string> getPackageNamesForUids(
const std::vector<uid_t>& uids) = 0;
@@ -59,7 +60,11 @@
protected:
virtual android::base::Result<void> initWatchdogServiceHelper(
const android::sp<IWatchdogServiceHelperInterface>& watchdogServiceHelper) = 0;
- virtual void setVendorPackagePrefixes(const std::unordered_set<std::string>& prefixes) = 0;
+ virtual void setPackageConfigurations(
+ const std::unordered_set<std::string>& vendorPackagePrefixes,
+ const std::unordered_map<
+ std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+ packagesToAppCategories) = 0;
private:
friend class ServiceManager;
@@ -75,13 +80,13 @@
* TODO(b/158131194): Extend IUidObserver in WatchdogBinderMediator and use the onUidGone API to
* keep the local mapping cache up-to-date.
*/
-class PackageInfoResolver : public IPackageInfoResolverInterface {
+class PackageInfoResolver : public IPackageInfoResolver {
public:
/*
* Initializes the PackageInfoResolver's singleton instance only on the first call. Main thread
* should make the first call as this method doesn't offer multi-threading protection.
*/
- static sp<IPackageInfoResolverInterface> getInstance();
+ static sp<IPackageInfoResolver> getInstance();
/*
* Resolves the given |uids| and returns a mapping of uids to package names. If the mapping
@@ -109,7 +114,11 @@
android::base::Result<void> initWatchdogServiceHelper(
const android::sp<IWatchdogServiceHelperInterface>& watchdogServiceHelper);
- void setVendorPackagePrefixes(const std::unordered_set<std::string>& prefixes);
+ virtual void setPackageConfigurations(
+ const std::unordered_set<std::string>& vendorPackagePrefixes,
+ const std::unordered_map<
+ std::string, android::automotive::watchdog::internal::ApplicationCategoryType>&
+ packagesToAppCategories);
private:
// PackageInfoResolver instance can only be obtained via |getInstance|.
@@ -136,6 +145,9 @@
std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>
mUidToPackageInfoMapping GUARDED_BY(mRWMutex);
std::vector<std::string> mVendorPackagePrefixes GUARDED_BY(mRWMutex);
+ std::unordered_map<std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>
+ mPackagesToAppCategories GUARDED_BY(mRWMutex);
friend class ServiceManager;
friend class IoOveruseMonitor;
diff --git a/cpp/watchdog/server/src/ServiceManager.cpp b/cpp/watchdog/server/src/ServiceManager.cpp
index 7e8e93b..6bcba40 100644
--- a/cpp/watchdog/server/src/ServiceManager.cpp
+++ b/cpp/watchdog/server/src/ServiceManager.cpp
@@ -26,7 +26,6 @@
namespace watchdog {
using ::android::sp;
-using ::android::String16;
using ::android::automotive::watchdog::WatchdogPerfService;
using ::android::automotive::watchdog::WatchdogProcessService;
using ::android::base::Error;
@@ -48,7 +47,7 @@
* by calling the getInstance method before starting other service as they may access
* PackageInfoResolver's instance during initialization.
*/
- sp<IPackageInfoResolverInterface> packageInfoResolver = PackageInfoResolver::getInstance();
+ sp<IPackageInfoResolver> packageInfoResolver = PackageInfoResolver::getInstance();
if (const auto result = startProcessAnrMonitor(looper); !result.ok()) {
return result;
}
diff --git a/cpp/watchdog/server/src/UidIoStats.cpp b/cpp/watchdog/server/src/UidIoStats.cpp
index 31cd0d9..ce7b351 100644
--- a/cpp/watchdog/server/src/UidIoStats.cpp
+++ b/cpp/watchdog/server/src/UidIoStats.cpp
@@ -113,11 +113,16 @@
mDeltaUidIoUsages.clear();
for (const auto& it : *uidIoUsages) {
- const UidIoUsage& curUsage = it.second;
- mDeltaUidIoUsages[it.first] = curUsage;
- if (mLatestUidIoUsages.find(it.first) != mLatestUidIoUsages.end()) {
- mDeltaUidIoUsages[it.first] -= mLatestUidIoUsages[it.first];
+ UidIoUsage curUsage = it.second;
+ if (curUsage.ios.isZero()) {
+ continue;
}
+ if (mLatestUidIoUsages.find(it.first) != mLatestUidIoUsages.end()) {
+ if (curUsage -= mLatestUidIoUsages[it.first]; curUsage.ios.isZero()) {
+ continue;
+ }
+ }
+ mDeltaUidIoUsages[it.first] = curUsage;
}
mLatestUidIoUsages = *uidIoUsages;
return {};
diff --git a/cpp/watchdog/server/src/UidIoStats.h b/cpp/watchdog/server/src/UidIoStats.h
index c6e87d1..3cc6a76 100644
--- a/cpp/watchdog/server/src/UidIoStats.h
+++ b/cpp/watchdog/server/src/UidIoStats.h
@@ -18,6 +18,7 @@
#define CPP_WATCHDOG_SERVER_SRC_UIDIOSTATS_H_
#include <android-base/result.h>
+#include <android-base/stringprintf.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -87,6 +88,10 @@
ios -= rhs.ios;
return *this;
}
+ bool operator==(const UidIoUsage& rhs) const { return uid == rhs.uid && ios == rhs.ios; }
+ std::string toString() const {
+ return android::base::StringPrintf("Uid: %d, Usage: {%s}", uid, ios.toString().c_str());
+ }
};
class UidIoStats : public RefBase {
diff --git a/cpp/watchdog/server/src/WatchdogBinderMediator.cpp b/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
index b27d9a9..0a4eb25 100644
--- a/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
+++ b/cpp/watchdog/server/src/WatchdogBinderMediator.cpp
@@ -32,6 +32,7 @@
using ::android::defaultServiceManager;
using ::android::IBinder;
using ::android::sp;
+using ::android::String16;
using ::android::base::Error;
using ::android::base::Join;
using ::android::base::ParseUint;
@@ -170,7 +171,6 @@
ALOGW("Failed to dump I/O perf collection: %s", ret.error().message().c_str());
return ret.error().code();
}
- // TODO(b/167240592): Add a dump call to I/O overuse monitor and relevant tests.
return OK;
}
diff --git a/cpp/watchdog/server/src/WatchdogBinderMediator.h b/cpp/watchdog/server/src/WatchdogBinderMediator.h
index e470290..63b687b 100644
--- a/cpp/watchdog/server/src/WatchdogBinderMediator.h
+++ b/cpp/watchdog/server/src/WatchdogBinderMediator.h
@@ -66,7 +66,7 @@
~WatchdogBinderMediator() { terminate(); }
// Implements ICarWatchdog.aidl APIs.
- status_t dump(int fd, const Vector<String16>& args) override;
+ status_t dump(int fd, const Vector<android::String16>& args) override;
android::binder::Status registerClient(const android::sp<ICarWatchdogClient>& client,
TimeoutLength timeout) override;
android::binder::Status unregisterClient(
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
index 0ed7cb8..556f9f1 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.cpp
@@ -34,9 +34,10 @@
using aawi::ComponentType;
using aawi::ICarWatchdogServiceForSystem;
-using aawi::IoOveruseConfiguration;
using aawi::PackageResourceOveruseAction;
+using aawi::ResourceOveruseConfiguration;
using ::android::sp;
+using ::android::String16;
using ::android::binder::Status;
namespace {
@@ -65,6 +66,18 @@
return mBinderMediator->dump(fd, args);
}
+void WatchdogInternalHandler::checkAndRegisterIoOveruseMonitor() {
+ if (mIoOveruseMonitor->isInitialized()) {
+ return;
+ }
+ if (const auto result = mWatchdogPerfService->registerDataProcessor(mIoOveruseMonitor);
+ !result.ok()) {
+ ALOGE("Failed to register I/O overuse monitor to watchdog performance service: %s",
+ result.error().message().c_str());
+ }
+ return;
+}
+
Status WatchdogInternalHandler::registerCarWatchdogService(
const sp<ICarWatchdogServiceForSystem>& service) {
Status status = checkSystemUser();
@@ -74,6 +87,12 @@
if (service == nullptr) {
return fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
}
+ /*
+ * I/O overuse monitor reads from system, vendor, and data partitions during initialization.
+ * When CarService is running these partitions are available to read, thus register the I/O
+ * overuse monitor on processing the request to register CarService.
+ */
+ checkAndRegisterIoOveruseMonitor();
return mWatchdogServiceHelper->registerService(service);
}
@@ -167,19 +186,6 @@
if (const auto result = mWatchdogPerfService->onBootFinished(); !result.ok()) {
return fromExceptionCode(result.error().code(), result.error().message());
}
- /*
- * I/O overuse monitor reads from data partition on init so register the I/O
- * overuse monitor only on boot-complete.
- *
- * TODO(b/167240592): Uncomment the below code block after the I/O overuse monitor
- * is completely implemented.
- * if (const auto result
- * = mWatchdogPerfService->registerDataProcessor(mIoOveruseMonitor);
- * !result.ok()) {
- * ALOGW("Failed to register I/O overuse monitor to watchdog performance "
- * "service: %s", result.error().message().c_str());
- * }
- */
}
return Status::ok();
}
@@ -188,13 +194,30 @@
StringPrintf("Invalid state change type %d", type));
}
-Status WatchdogInternalHandler::updateIoOveruseConfiguration(ComponentType type,
- const IoOveruseConfiguration& config) {
+Status WatchdogInternalHandler::updateResourceOveruseConfigurations(
+ const std::vector<ResourceOveruseConfiguration>& configs) {
Status status = checkSystemUser();
if (!status.isOk()) {
return status;
}
- if (const auto result = mIoOveruseMonitor->updateIoOveruseConfiguration(type, config);
+ // Maybe retry registring I/O overuse monitor if failed to initialize previously.
+ checkAndRegisterIoOveruseMonitor();
+ if (const auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
+ !result.ok()) {
+ return fromExceptionCode(result.error().code(), result.error().message());
+ }
+ return Status::ok();
+}
+
+Status WatchdogInternalHandler::getResourceOveruseConfigurations(
+ std::vector<ResourceOveruseConfiguration>* configs) {
+ Status status = checkSystemUser();
+ if (!status.isOk()) {
+ return status;
+ }
+ // Maybe retry registring I/O overuse monitor if failed to initialize previously.
+ checkAndRegisterIoOveruseMonitor();
+ if (const auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs);
!result.ok()) {
return fromExceptionCode(result.error().code(), result.error().message());
}
diff --git a/cpp/watchdog/server/src/WatchdogInternalHandler.h b/cpp/watchdog/server/src/WatchdogInternalHandler.h
index 9254ed6..098b0dd 100644
--- a/cpp/watchdog/server/src/WatchdogInternalHandler.h
+++ b/cpp/watchdog/server/src/WatchdogInternalHandler.h
@@ -26,12 +26,13 @@
#include <android/automotive/watchdog/internal/ComponentType.h>
#include <android/automotive/watchdog/internal/ICarWatchdogMonitor.h>
#include <android/automotive/watchdog/internal/ICarWatchdogServiceForSystem.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
#include <android/automotive/watchdog/internal/PackageResourceOveruseAction.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
#include <android/automotive/watchdog/internal/StateType.h>
#include <binder/Status.h>
#include <gtest/gtest_prod.h>
#include <utils/Errors.h>
+#include <utils/String16.h>
#include <utils/Vector.h>
namespace android {
@@ -55,7 +56,7 @@
mIoOveruseMonitor(ioOveruseMonitor) {}
~WatchdogInternalHandler() { terminate(); }
- status_t dump(int fd, const Vector<String16>& args) override;
+ status_t dump(int fd, const Vector<android::String16>& args) override;
android::binder::Status registerCarWatchdogService(
const android::sp<
android::automotive::watchdog::internal::ICarWatchdogServiceForSystem>& service)
@@ -81,9 +82,13 @@
android::binder::Status notifySystemStateChange(
android::automotive::watchdog::internal::StateType type, int32_t arg1,
int32_t arg2) override;
- android::binder::Status updateIoOveruseConfiguration(
- android::automotive::watchdog::internal::ComponentType type,
- const android::automotive::watchdog::internal::IoOveruseConfiguration& config) override;
+ android::binder::Status updateResourceOveruseConfigurations(
+ const std::vector<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>& configs)
+ override;
+ android::binder::Status getResourceOveruseConfigurations(
+ std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*
+ configs) override;
android::binder::Status actionTakenOnResourceOveruse(
const std::vector<
android::automotive::watchdog::internal::PackageResourceOveruseAction>&
@@ -99,6 +104,8 @@
}
private:
+ void checkAndRegisterIoOveruseMonitor();
+
android::sp<WatchdogBinderMediator> mBinderMediator;
android::sp<IWatchdogServiceHelperInterface> mWatchdogServiceHelper;
android::sp<WatchdogProcessService> mWatchdogProcessService;
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.cpp b/cpp/watchdog/server/src/WatchdogPerfService.cpp
index 79177ad..214a16c 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.cpp
+++ b/cpp/watchdog/server/src/WatchdogPerfService.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "carwatchdogd"
+#define DEBUG false // STOPSHIP if true.
#include "WatchdogPerfService.h"
@@ -36,6 +37,7 @@
namespace watchdog {
using ::android::String16;
+using ::android::String8;
using ::android::base::Error;
using ::android::base::Join;
using ::android::base::ParseUint;
@@ -140,6 +142,9 @@
}
Mutex::Autolock lock(mMutex);
mDataProcessors.push_back(processor);
+ if (DEBUG) {
+ ALOGD("Successfully registered %s to %s", processor->name().c_str(), kServiceName);
+ }
return {};
}
@@ -241,6 +246,9 @@
}
if (mCollectionThread.joinable()) {
mCollectionThread.join();
+ if (DEBUG) {
+ ALOGD("%s collection thread terminated", kServiceName);
+ }
}
}
@@ -260,6 +268,9 @@
mBoottimeCollection.lastUptime = mHandlerLooper->now();
mHandlerLooper->removeMessages(this);
mHandlerLooper->sendMessage(this, SwitchMessage::END_BOOTTIME_COLLECTION);
+ if (DEBUG) {
+ ALOGD("Boot-time event finished");
+ }
return {};
}
@@ -471,6 +482,9 @@
}
}
+ if (DEBUG) {
+ ALOGD("Custom event finished");
+ }
WriteStringToFd(kDumpMajorDelimiter, fd);
return {};
}
@@ -564,6 +578,9 @@
toString(mCurrCollectionEvent));
return {};
}
+ if (DEBUG) {
+ ALOGD("Processing %s collection event", toString(metadata->eventType));
+ }
if (metadata->interval < kMinEventInterval) {
return Error()
<< "Collection interval of "
@@ -636,6 +653,9 @@
if (metadata->eventType != static_cast<int>(EventType::PERIODIC_MONITOR)) {
return Error() << "Invalid monitor event " << toString(metadata->eventType);
}
+ if (DEBUG) {
+ ALOGD("Processing %s monitor event", toString(metadata->eventType));
+ }
if (metadata->interval < kMinEventInterval) {
return Error()
<< "Monitor interval of "
diff --git a/cpp/watchdog/server/src/WatchdogPerfService.h b/cpp/watchdog/server/src/WatchdogPerfService.h
index c44659b..0551d35 100644
--- a/cpp/watchdog/server/src/WatchdogPerfService.h
+++ b/cpp/watchdog/server/src/WatchdogPerfService.h
@@ -171,7 +171,8 @@
// 1. Starts a custom collection.
// 2. Or ends the current custom collection and dumps the collected data.
// Returns any error observed during the dump generation.
- virtual android::base::Result<void> onCustomCollection(int fd, const Vector<String16>& args);
+ virtual android::base::Result<void> onCustomCollection(int fd,
+ const Vector<android::String16>& args);
// Generates a dump from the boot-time and periodic collection events.
virtual android::base::Result<void> onDump(int fd);
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.cpp b/cpp/watchdog/server/src/WatchdogProcessService.cpp
index 7af7ecc..952c83e 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.cpp
+++ b/cpp/watchdog/server/src/WatchdogProcessService.cpp
@@ -48,6 +48,7 @@
using aawi::ICarWatchdogServiceForSystem;
using ::android::IBinder;
using ::android::sp;
+using ::android::String16;
using ::android::base::Error;
using ::android::base::GetProperty;
using ::android::base::ReadFileToString;
diff --git a/cpp/watchdog/server/src/WatchdogProcessService.h b/cpp/watchdog/server/src/WatchdogProcessService.h
index c4ae2cb..288f99e 100644
--- a/cpp/watchdog/server/src/WatchdogProcessService.h
+++ b/cpp/watchdog/server/src/WatchdogProcessService.h
@@ -50,7 +50,8 @@
android::base::Result<void> start();
void terminate();
- virtual android::base::Result<void> dump(int fd, const android::Vector<String16>& args);
+ virtual android::base::Result<void> dump(int fd,
+ const android::Vector<android::String16>& args);
void doHealthCheck(int what);
virtual android::base::Result<void> registerWatchdogServiceHelper(
diff --git a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
index f89942e..03f3305 100644
--- a/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
+++ b/cpp/watchdog/server/src/WatchdogServiceHelper.cpp
@@ -34,7 +34,6 @@
using aawi::PackageIoOveruseStats;
using ::android::IBinder;
using ::android::sp;
-using ::android::String16;
using ::android::wp;
using ::android::base::Error;
using ::android::base::Result;
@@ -180,21 +179,17 @@
Status WatchdogServiceHelper::getPackageInfosForUids(
const std::vector<int32_t>& uids, const std::vector<std::string>& vendorPackagePrefixes,
std::vector<PackageInfo>* packageInfos) {
- /*
- * The expected number of vendor package prefixes is in the order of 10s. Thus the overhead of
- * forwarding these in each get call is very low.
- */
- std::vector<String16> prefixes;
- for (const auto& prefix : vendorPackagePrefixes) {
- prefixes.push_back(String16(prefix.c_str()));
- }
sp<ICarWatchdogServiceForSystem> service;
if (std::shared_lock readLock(mRWMutex); mService == nullptr) {
return fromExceptionCode(Status::EX_ILLEGAL_STATE, "Watchdog service is not initialized");
} else {
service = mService;
}
- return service->getPackageInfosForUids(uids, prefixes, packageInfos);
+ /*
+ * The expected number of vendor package prefixes is in the order of 10s. Thus the overhead of
+ * forwarding these in each get call is very low.
+ */
+ return service->getPackageInfosForUids(uids, vendorPackagePrefixes, packageInfos);
}
Status WatchdogServiceHelper::latestIoOveruseStats(
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index e1602f8..433f027 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -18,7 +18,6 @@
#include <android-base/strings.h>
#include <gmock/gmock.h>
-#include <utils/String8.h>
#include <inttypes.h>
@@ -26,40 +25,38 @@
namespace automotive {
namespace watchdog {
-using ::android::String16;
-using ::android::String8;
+using ::android::sp;
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
using ::android::automotive::watchdog::internal::IoOveruseConfiguration;
using ::android::automotive::watchdog::internal::PackageInfo;
+using ::android::automotive::watchdog::internal::PackageMetadata;
using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
using ::android::automotive::watchdog::internal::UidType;
+using ::android::base::StringAppendF;
using ::android::base::StringPrintf;
+using ::testing::AllOf;
using ::testing::AnyOf;
+using ::testing::ExplainMatchResult;
+using ::testing::Field;
using ::testing::IsEmpty;
+using ::testing::Matcher;
using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
using ::testing::Value;
namespace {
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
- const int64_t fgBytes,
- const int64_t bgBytes,
- const int64_t garageModeBytes) {
- PerStateIoOveruseThreshold threshold;
- threshold.name = String16(String8(name.c_str()));
- threshold.perStateWriteBytes.foregroundBytes = fgBytes;
- threshold.perStateWriteBytes.backgroundBytes = bgBytes;
- threshold.perStateWriteBytes.garageModeBytes = garageModeBytes;
- return threshold;
-}
-
-PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
- const int64_t fgBytes,
- const int64_t bgBytes,
- const int64_t garageModeBytes) {
- return toPerStateIoOveruseThreshold(toString(type), fgBytes, bgBytes, garageModeBytes);
+PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
+ const int64_t garageModeBytes) {
+ PerStateBytes perStateBytes;
+ perStateBytes.foregroundBytes = fgBytes;
+ perStateBytes.backgroundBytes = bgBytes;
+ perStateBytes.garageModeBytes = garageModeBytes;
+ return perStateBytes;
}
IoOveruseAlertThreshold toIoOveruseAlertThreshold(const int64_t durationInSeconds,
@@ -70,430 +67,726 @@
return threshold;
}
-std::vector<String16> toString16Vector(const std::vector<std::string>& values) {
- std::vector<String16> output;
- for (const auto v : values) {
- output.emplace_back(String16(String8(v.c_str())));
+const PerStateBytes SYSTEM_COMPONENT_LEVEL_THRESHOLDS = toPerStateBytes(200, 100, 500);
+const PerStateBytes SYSTEM_PACKAGE_A_THRESHOLDS = toPerStateBytes(600, 400, 1000);
+const PerStateBytes SYSTEM_PACKAGE_B_THRESHOLDS = toPerStateBytes(1200, 800, 1500);
+const PerStateBytes VENDOR_COMPONENT_LEVEL_THRESHOLDS = toPerStateBytes(100, 50, 900);
+const PerStateBytes VENDOR_PACKAGE_A_THRESHOLDS = toPerStateBytes(800, 300, 500);
+const PerStateBytes VENDOR_PKG_B_THRESHOLDS = toPerStateBytes(1600, 600, 1000);
+const PerStateBytes MAPS_THRESHOLDS = toPerStateBytes(700, 900, 1300);
+const PerStateBytes MEDIA_THRESHOLDS = toPerStateBytes(1800, 1900, 2100);
+const PerStateBytes THIRD_PARTY_COMPONENT_LEVEL_THRESHOLDS = toPerStateBytes(300, 150, 1900);
+const std::vector<IoOveruseAlertThreshold> ALERT_THRESHOLDS = {toIoOveruseAlertThreshold(5, 200),
+ toIoOveruseAlertThreshold(30,
+ 40000)};
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+ const PerStateBytes& perStateBytes) {
+ PerStateIoOveruseThreshold threshold;
+ threshold.name = name;
+ threshold.perStateWriteBytes = perStateBytes;
+ return threshold;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+ const PerStateBytes& perStateBytes) {
+ return toPerStateIoOveruseThreshold(toString(type), perStateBytes);
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+ const int64_t fgBytes,
+ const int64_t bgBytes,
+ const int64_t garageModeBytes) {
+ PerStateIoOveruseThreshold threshold;
+ threshold.name = name;
+ threshold.perStateWriteBytes = toPerStateBytes(fgBytes, bgBytes, garageModeBytes);
+ return threshold;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+ const int64_t fgBytes,
+ const int64_t bgBytes,
+ const int64_t garageModeBytes) {
+ return toPerStateIoOveruseThreshold(toString(type), fgBytes, bgBytes, garageModeBytes);
+}
+
+PackageMetadata toPackageMetadata(std::string packageName, ApplicationCategoryType type) {
+ PackageMetadata meta;
+ meta.packageName = packageName;
+ meta.appCategoryType = type;
+ return meta;
+}
+
+std::unordered_map<std::string, ApplicationCategoryType> toPackageToAppCategoryMappings(
+ const std::vector<PackageMetadata>& metas) {
+ std::unordered_map<std::string, ApplicationCategoryType> mappings;
+ for (const auto& meta : metas) {
+ mappings[meta.packageName] = meta.appCategoryType;
}
- return output;
+ return mappings;
}
PackageInfo constructPackageInfo(
const char* packageName, const ComponentType componentType,
const ApplicationCategoryType appCategoryType = ApplicationCategoryType::OTHERS) {
PackageInfo packageInfo;
- packageInfo.packageIdentifier.name = String16(packageName);
+ packageInfo.packageIdentifier.name = packageName;
packageInfo.uidType = UidType::APPLICATION;
packageInfo.componentType = componentType;
packageInfo.appCategoryType = appCategoryType;
return packageInfo;
}
-struct PackageConfigTest {
- PackageInfo packageInfo;
- PerStateBytes expectedThreshold;
- bool expectedIsSafeToKill;
-};
+ResourceOveruseConfiguration constructResourceOveruseConfig(
+ const ComponentType type, const std::vector<std::string>&& safeToKill,
+ const std::vector<std::string>&& vendorPrefixes,
+ const std::vector<PackageMetadata> packageMetadata,
+ const IoOveruseConfiguration& ioOveruseConfiguration) {
+ ResourceOveruseConfiguration resourceOveruseConfig;
+ resourceOveruseConfig.componentType = type;
+ resourceOveruseConfig.safeToKillPackages = safeToKill;
+ resourceOveruseConfig.vendorPackagePrefixes = vendorPrefixes;
+ resourceOveruseConfig.packageMetadata = packageMetadata;
+ ResourceSpecificConfiguration config;
+ config.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(ioOveruseConfiguration);
+ resourceOveruseConfig.resourceSpecificConfigurations.push_back(config);
+ return resourceOveruseConfig;
+}
+
+IoOveruseConfiguration constructIoOveruseConfig(
+ PerStateIoOveruseThreshold componentLevel,
+ const std::vector<PerStateIoOveruseThreshold>& packageSpecific,
+ const std::vector<PerStateIoOveruseThreshold>& categorySpecific,
+ const std::vector<IoOveruseAlertThreshold>& systemWide) {
+ IoOveruseConfiguration config;
+ config.componentLevelThresholds = componentLevel;
+ config.packageSpecificThresholds = packageSpecific;
+ config.categorySpecificThresholds = categorySpecific;
+ config.systemWideThresholds = systemWide;
+ return config;
+}
+
+std::string toString(std::vector<ResourceOveruseConfiguration> configs) {
+ std::string buffer;
+ StringAppendF(&buffer, "[");
+ for (const auto& config : configs) {
+ if (buffer.size() > 1) {
+ StringAppendF(&buffer, ",\n");
+ }
+ StringAppendF(&buffer, "%s", config.toString().c_str());
+ }
+ StringAppendF(&buffer, "]\n");
+ return buffer;
+}
+
+MATCHER_P(IsIoOveruseConfiguration, config, "") {
+ return arg.componentLevelThresholds == config.componentLevelThresholds &&
+ ExplainMatchResult(UnorderedElementsAreArray(config.packageSpecificThresholds),
+ arg.packageSpecificThresholds, result_listener) &&
+ ExplainMatchResult(UnorderedElementsAreArray(config.categorySpecificThresholds),
+ arg.categorySpecificThresholds, result_listener) &&
+ ExplainMatchResult(UnorderedElementsAreArray(config.systemWideThresholds),
+ arg.systemWideThresholds, result_listener);
+}
+
+MATCHER_P(IsResourceSpecificConfiguration, config, "") {
+ if (arg.getTag() != config.getTag()) {
+ return false;
+ }
+ // Reference with the actual datatype so the templated get method can be called.
+ const ResourceSpecificConfiguration& expected = config;
+ const ResourceSpecificConfiguration& actual = arg;
+ switch (arg.getTag()) {
+ case ResourceSpecificConfiguration::ioOveruseConfiguration: {
+ const auto& expectedIoConfig =
+ expected.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+ const auto& actualIoConfig =
+ actual.get<ResourceSpecificConfiguration::ioOveruseConfiguration>();
+ return ExplainMatchResult(IsIoOveruseConfiguration(expectedIoConfig), actualIoConfig,
+ result_listener);
+ }
+ default:
+ return true;
+ }
+}
+
+Matcher<const ResourceOveruseConfiguration> IsResourceOveruseConfiguration(
+ const ResourceOveruseConfiguration& config) {
+ std::vector<Matcher<const ResourceSpecificConfiguration>> matchers;
+ for (const auto& resourceSpecificConfig : config.resourceSpecificConfigurations) {
+ matchers.push_back(IsResourceSpecificConfiguration(resourceSpecificConfig));
+ }
+
+ return AllOf(Field(&ResourceOveruseConfiguration::componentType, config.componentType),
+ Field(&ResourceOveruseConfiguration::safeToKillPackages,
+ UnorderedElementsAreArray(config.safeToKillPackages)),
+ Field(&ResourceOveruseConfiguration::vendorPackagePrefixes,
+ UnorderedElementsAreArray(config.vendorPackagePrefixes)),
+ Field(&ResourceOveruseConfiguration::resourceSpecificConfigurations,
+ UnorderedElementsAreArray(matchers)));
+}
+
+std::vector<Matcher<const ResourceOveruseConfiguration>> IsResourceOveruseConfigurations(
+ const std::vector<ResourceOveruseConfiguration>& configs) {
+ std::vector<Matcher<const ResourceOveruseConfiguration>> matchers;
+ for (const auto config : configs) {
+ matchers.push_back(IsResourceOveruseConfiguration(config));
+ }
+ return matchers;
+}
+
+ResourceOveruseConfiguration sampleSystemConfig() {
+ auto systemIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::SYSTEM,
+ SYSTEM_COMPONENT_LEVEL_THRESHOLDS),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("systemPackageA", SYSTEM_PACKAGE_A_THRESHOLDS),
+ toPerStateIoOveruseThreshold("systemPackageB", SYSTEM_PACKAGE_B_THRESHOLDS)},
+ /*categorySpecific=*/{},
+ /*systemWide=*/ALERT_THRESHOLDS);
+ return constructResourceOveruseConfig(ComponentType::SYSTEM, /*safeToKill=*/{"systemPackageA"},
+ /*vendorPrefixes=*/{},
+ /*packageMetadata=*/
+ {toPackageMetadata("systemPackageA",
+ ApplicationCategoryType::MEDIA),
+ toPackageMetadata("vendorPkgB",
+ ApplicationCategoryType::MAPS)},
+ systemIoConfig);
+}
+
+ResourceOveruseConfiguration sampleVendorConfig() {
+ auto vendorIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::VENDOR,
+ VENDOR_COMPONENT_LEVEL_THRESHOLDS),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("vendorPackageA", VENDOR_PACKAGE_A_THRESHOLDS),
+ toPerStateIoOveruseThreshold("vendorPkgB", VENDOR_PKG_B_THRESHOLDS)},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", MAPS_THRESHOLDS),
+ toPerStateIoOveruseThreshold("MEDIA", MEDIA_THRESHOLDS)},
+ /*systemWide=*/{});
+ return constructResourceOveruseConfig(ComponentType::VENDOR,
+ /*safeToKill=*/{"vendorPackageA"},
+ /*vendorPrefixes=*/{"vendorPackage"},
+ /*packageMetadata=*/
+ {toPackageMetadata("systemPackageA",
+ ApplicationCategoryType::MEDIA),
+ toPackageMetadata("vendorPkgB",
+ ApplicationCategoryType::MAPS)},
+ vendorIoConfig);
+}
+
+ResourceOveruseConfiguration sampleThirdPartyConfig() {
+ auto thirdPartyIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/
+ toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY,
+ THIRD_PARTY_COMPONENT_LEVEL_THRESHOLDS),
+ /*packageSpecific=*/{}, /*categorySpecific=*/{}, /*systemWide=*/{});
+ return constructResourceOveruseConfig(ComponentType::THIRD_PARTY, /*safeToKill=*/{},
+ /*vendorPrefixes=*/{}, /*packageMetadata=*/{},
+ thirdPartyIoConfig);
+}
+
+sp<IoOveruseConfigs> sampleIoOveruseConfigs() {
+ sp<IoOveruseConfigs> ioOveruseConfigs = new IoOveruseConfigs();
+ EXPECT_RESULT_OK(ioOveruseConfigs->update(
+ {sampleSystemConfig(), sampleVendorConfig(), sampleThirdPartyConfig()}));
+ return ioOveruseConfigs;
+}
} // namespace
TEST(IoOveruseConfigsTest, TestUpdateWithValidConfigs) {
- IoOveruseConfiguration systemComponentConfig;
- systemComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 200, 100, 500);
- systemComponentConfig.packageSpecificThresholds =
- {toPerStateIoOveruseThreshold("systemPackageA", 600, 400, 1000),
- toPerStateIoOveruseThreshold("systemPackageB", 1200, 800, 1500)};
- systemComponentConfig.safeToKillPackages = toString16Vector({"systemPackageA"});
- systemComponentConfig.systemWideThresholds = {toIoOveruseAlertThreshold(5, 200),
- toIoOveruseAlertThreshold(30, 40000)};
-
- IoOveruseConfiguration vendorComponentConfig;
- vendorComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::VENDOR, 100, 50, 900);
- vendorComponentConfig.packageSpecificThresholds =
- {toPerStateIoOveruseThreshold("vendorPackageA", 800, 300, 500),
- toPerStateIoOveruseThreshold("vendorPkgB", 1600, 600, 1000)};
- vendorComponentConfig.safeToKillPackages =
- toString16Vector({"vendorPackageGeneric", "vendorPackageA"});
- vendorComponentConfig.vendorPackagePrefixes = toString16Vector({"vendorPackage", "vendorPkg"});
- vendorComponentConfig.categorySpecificThresholds = {toPerStateIoOveruseThreshold("MAPS", 600,
- 400, 1000),
- toPerStateIoOveruseThreshold("MEDIA", 1200,
- 800, 1500)};
-
- IoOveruseConfiguration thirdPartyComponentConfig;
- thirdPartyComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 300, 150, 1900);
+ auto systemResourceConfig = sampleSystemConfig();
+ auto vendorResourceConfig = sampleVendorConfig();
+ auto thirdPartyResourceConfig = sampleThirdPartyConfig();
IoOveruseConfigs ioOveruseConfigs;
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::SYSTEM, systemComponentConfig));
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::VENDOR, vendorComponentConfig));
- ASSERT_RESULT_OK(
- ioOveruseConfigs.update(ComponentType::THIRD_PARTY, thirdPartyComponentConfig));
+ ASSERT_RESULT_OK(ioOveruseConfigs.update(
+ {systemResourceConfig, vendorResourceConfig, thirdPartyResourceConfig}));
- std::vector<PackageConfigTest> packageConfigTests = {
- {.packageInfo = constructPackageInfo("systemPackageGeneric", ComponentType::SYSTEM),
- .expectedThreshold = systemComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("systemPackageA", ComponentType::SYSTEM),
- .expectedThreshold =
- systemComponentConfig.packageSpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("systemPackageB", ComponentType::SYSTEM,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold =
- systemComponentConfig.packageSpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("systemPackageC", ComponentType::SYSTEM,
- ApplicationCategoryType::MAPS),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPackageGeneric", ComponentType::VENDOR),
- .expectedThreshold = vendorComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("vendorPackageA", ComponentType::VENDOR),
- .expectedThreshold =
- vendorComponentConfig.packageSpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("vendorPkgB", ComponentType::VENDOR,
- ApplicationCategoryType::MAPS),
- .expectedThreshold =
- vendorComponentConfig.packageSpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPackageC", ComponentType::VENDOR,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPkgB", ComponentType::THIRD_PARTY),
- .expectedThreshold =
- thirdPartyComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("3pMapsPackage", ComponentType::THIRD_PARTY,
- ApplicationCategoryType::MAPS),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("3pMediaPackage", ComponentType::THIRD_PARTY,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- };
+ vendorResourceConfig.vendorPackagePrefixes.push_back("vendorPkgB");
+ std::vector<ResourceOveruseConfiguration> expected = {systemResourceConfig,
+ vendorResourceConfig,
+ thirdPartyResourceConfig};
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
- EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(),
- UnorderedElementsAre(systemComponentConfig.systemWideThresholds[0],
- systemComponentConfig.systemWideThresholds[1]));
-
- EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(),
- UnorderedElementsAre(std::string(String8(
- vendorComponentConfig.vendorPackagePrefixes[0])),
- std::string(String8(
- vendorComponentConfig.vendorPackagePrefixes[1]))));
+ EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ << "Expected: " << toString(expected) << "Actual:" << toString(actual);
// Check whether previous configs are overwritten.
- systemComponentConfig = {};
- systemComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 300, 400, 600);
- systemComponentConfig.packageSpecificThresholds =
+ auto systemIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 300, 400, 600),
+ /*packageSpecific=*/
{toPerStateIoOveruseThreshold("systemPackageC", 700, 100, 200),
- toPerStateIoOveruseThreshold("systemPackageC", 300, 200, 300)};
- systemComponentConfig.safeToKillPackages = toString16Vector({"systemPackageC"});
- systemComponentConfig.systemWideThresholds = {toIoOveruseAlertThreshold(6, 4),
- toIoOveruseAlertThreshold(6, 10)};
+ toPerStateIoOveruseThreshold("systemPackageC", 300, 200, 300)},
+ /*categorySpecific=*/{},
+ /*systemWide=*/
+ {toIoOveruseAlertThreshold(6, 4), toIoOveruseAlertThreshold(6, 10)});
+ systemResourceConfig =
+ constructResourceOveruseConfig(ComponentType::SYSTEM, /*safeToKill=*/{"systemPackageC"},
+ /*vendorPrefixes=*/{}, /*packageMetadata=*/{},
+ systemIoConfig);
- vendorComponentConfig = {};
- vendorComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::VENDOR, 10, 90, 300);
/*
* Not adding any safe to kill packages list or package specific thresholds should clear
* previous entries after update.
*/
- vendorComponentConfig.vendorPackagePrefixes = toString16Vector({"vendorPackage", "vendorPkg"});
- vendorComponentConfig
- .categorySpecificThresholds = {toPerStateIoOveruseThreshold("MAPS", 800, 900, 2000),
- toPerStateIoOveruseThreshold("MEDIA", 1200, 800, 1500),
- toPerStateIoOveruseThreshold("MEDIA", 1400, 1600, 2000)};
+ auto vendorIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::VENDOR, 10, 90, 300),
+ /*packageSpecific=*/{},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", 800, 900, 2000),
+ toPerStateIoOveruseThreshold("MEDIA", 1800, 1900, 2100),
+ toPerStateIoOveruseThreshold("MEDIA", 1400, 1600, 2000)},
+ /*systemWide=*/{});
+ vendorResourceConfig =
+ constructResourceOveruseConfig(ComponentType::VENDOR, /*safeToKill=*/{},
+ /*vendorPrefixes=*/{"vendorPackage", "vendorPkg"},
+ /*packageMetadata=*/{}, vendorIoConfig);
- thirdPartyComponentConfig = {};
- thirdPartyComponentConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 600, 300, 2300);
+ auto thirdPartyIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/
+ toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 600, 300, 2300),
+ /*packageSpecific=*/{}, /*categorySpecific=*/{}, /*systemWide=*/{});
+ thirdPartyResourceConfig =
+ constructResourceOveruseConfig(ComponentType::THIRD_PARTY, /*safeToKill=*/{},
+ /*vendorPrefixes=*/{}, /*packageMetadata=*/{},
+ thirdPartyIoConfig);
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::SYSTEM, systemComponentConfig));
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::VENDOR, vendorComponentConfig));
- ASSERT_RESULT_OK(
- ioOveruseConfigs.update(ComponentType::THIRD_PARTY, thirdPartyComponentConfig));
+ ASSERT_RESULT_OK(ioOveruseConfigs.update(
+ {systemResourceConfig, vendorResourceConfig, thirdPartyResourceConfig}));
- packageConfigTests = {
- {.packageInfo = constructPackageInfo("systemPackageA", ComponentType::SYSTEM),
- .expectedThreshold = systemComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("systemPackageC", ComponentType::SYSTEM),
- .expectedThreshold =
- systemComponentConfig.packageSpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("systemMapsPackage", ComponentType::SYSTEM,
- ApplicationCategoryType::MAPS),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPackageA", ComponentType::VENDOR),
- .expectedThreshold = vendorComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorMediaPackage", ComponentType::VENDOR,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold =
- vendorComponentConfig.categorySpecificThresholds[2].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("3pPackage", ComponentType::THIRD_PARTY),
- .expectedThreshold =
- thirdPartyComponentConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = true},
- };
+ systemIoConfig.packageSpecificThresholds.erase(
+ systemIoConfig.packageSpecificThresholds.begin());
+ systemIoConfig.systemWideThresholds.erase(systemIoConfig.systemWideThresholds.begin() + 1);
+ systemResourceConfig =
+ constructResourceOveruseConfig(ComponentType::SYSTEM, /*safeToKill=*/{"systemPackageC"},
+ /*vendorPrefixes=*/{}, /*packageMetadata=*/{},
+ systemIoConfig);
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ vendorIoConfig.categorySpecificThresholds.erase(
+ vendorIoConfig.categorySpecificThresholds.begin() + 1);
+ vendorResourceConfig =
+ constructResourceOveruseConfig(ComponentType::VENDOR, /*safeToKill=*/{},
+ /*vendorPrefixes=*/{"vendorPackage", "vendorPkg"},
+ /*packageMetadata=*/{}, vendorIoConfig);
- EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(),
- UnorderedElementsAre(AnyOf(systemComponentConfig.systemWideThresholds[0],
- systemComponentConfig.systemWideThresholds[1])));
+ expected = {systemResourceConfig, vendorResourceConfig, thirdPartyResourceConfig};
- EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(),
- UnorderedElementsAre(std::string(String8(
- vendorComponentConfig.vendorPackagePrefixes[0])),
- std::string(String8(
- vendorComponentConfig.vendorPackagePrefixes[1]))));
+ actual.clear();
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ << "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
TEST(IoOveruseConfigsTest, TestDefaultConfigWithoutUpdate) {
- std::vector<PackageConfigTest> packageConfigTests =
- {{.packageInfo = constructPackageInfo("systemPackage", ComponentType::SYSTEM),
- .expectedThreshold = defaultThreshold().perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPackage", ComponentType::VENDOR,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold = defaultThreshold().perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("3pPackage", ComponentType::THIRD_PARTY,
- ApplicationCategoryType::MAPS),
- .expectedThreshold = defaultThreshold().perStateWriteBytes,
- .expectedIsSafeToKill = true}};
+ PerStateBytes defaultPerStateBytes = defaultThreshold().perStateWriteBytes;
IoOveruseConfigs ioOveruseConfigs;
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ auto packageInfo = constructPackageInfo("systemPackage", ComponentType::SYSTEM);
+ EXPECT_THAT(ioOveruseConfigs.fetchThreshold(packageInfo), defaultPerStateBytes)
+ << "System package should have default threshold";
+ EXPECT_FALSE(ioOveruseConfigs.isSafeToKill(packageInfo))
+ << "System package shouldn't be killed by default";
+
+ packageInfo = constructPackageInfo("vendorPackage", ComponentType::VENDOR,
+ ApplicationCategoryType::MEDIA);
+ EXPECT_THAT(ioOveruseConfigs.fetchThreshold(packageInfo), defaultPerStateBytes)
+ << "Vendor package should have default threshold";
+ EXPECT_FALSE(ioOveruseConfigs.isSafeToKill(packageInfo))
+ << "Vendor package shouldn't be killed by default";
+
+ packageInfo = constructPackageInfo("3pPackage", ComponentType::THIRD_PARTY,
+ ApplicationCategoryType::MAPS);
+ EXPECT_THAT(ioOveruseConfigs.fetchThreshold(packageInfo), defaultPerStateBytes)
+ << "Third-party package should have default threshold";
+ EXPECT_TRUE(ioOveruseConfigs.isSafeToKill(packageInfo))
+ << "Third-party package should be killed by default";
EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(), IsEmpty());
EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(), IsEmpty());
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
}
TEST(IoOveruseConfigsTest, TestFailsUpdateOnInvalidComponentName) {
- IoOveruseConfiguration updateConfig;
- updateConfig.componentLevelThresholds =
+ IoOveruseConfiguration randomIoConfig;
+ randomIoConfig.componentLevelThresholds =
toPerStateIoOveruseThreshold("random name", 200, 100, 500);
IoOveruseConfigs ioOveruseConfigs;
- EXPECT_FALSE(ioOveruseConfigs.update(ComponentType::SYSTEM, updateConfig).ok());
+ EXPECT_FALSE(ioOveruseConfigs
+ .update({constructResourceOveruseConfig(ComponentType::SYSTEM, {}, {}, {},
+ randomIoConfig)})
+ .ok());
- EXPECT_FALSE(ioOveruseConfigs.update(ComponentType::VENDOR, updateConfig).ok());
+ EXPECT_FALSE(ioOveruseConfigs
+ .update({constructResourceOveruseConfig(ComponentType::VENDOR, {}, {}, {},
+ randomIoConfig)})
+ .ok());
- EXPECT_FALSE(ioOveruseConfigs.update(ComponentType::THIRD_PARTY, updateConfig).ok());
+ EXPECT_FALSE(ioOveruseConfigs
+ .update({constructResourceOveruseConfig(ComponentType::THIRD_PARTY, {}, {},
+ {}, randomIoConfig)})
+ .ok());
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
}
-TEST(IoOveruseConfigsTest, TestFailsUpdateOnInvalidConfigs) {
- IoOveruseConfiguration updateConfig;
- updateConfig.componentLevelThresholds =
+TEST(IoOveruseConfigsTest, TestFailsUpdateOnInvalidComponentLevelThresholds) {
+ IoOveruseConfiguration ioConfig;
+ ioConfig.componentLevelThresholds =
toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 0, 0, 0);
- const IoOveruseConfigs expected = {};
IoOveruseConfigs ioOveruseConfigs;
-
- EXPECT_FALSE(ioOveruseConfigs.update(ComponentType::THIRD_PARTY, updateConfig).ok())
+ EXPECT_FALSE(ioOveruseConfigs
+ .update({constructResourceOveruseConfig(ComponentType::THIRD_PARTY, {}, {},
+ {}, ioConfig)})
+ .ok())
<< "Should error on invalid component level thresholds";
- updateConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 100, 200, 300);
- updateConfig.systemWideThresholds = {toIoOveruseAlertThreshold(0, 0)};
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
- EXPECT_FALSE(ioOveruseConfigs.update(ComponentType::SYSTEM, updateConfig).ok())
+ EXPECT_THAT(actual, IsEmpty());
+}
+
+TEST(IoOveruseConfigsTest, TestFailsUpdateOnInvalidSystemWideAlertThresholds) {
+ IoOveruseConfiguration ioConfig;
+ ioConfig.componentLevelThresholds =
+ toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 100, 200, 300);
+ ioConfig.systemWideThresholds = {toIoOveruseAlertThreshold(0, 0)};
+
+ IoOveruseConfigs ioOveruseConfigs;
+ EXPECT_FALSE(ioOveruseConfigs
+ .update({constructResourceOveruseConfig(ComponentType::SYSTEM, {}, {}, {},
+ ioConfig)})
+ .ok())
<< "Should error on invalid system-wide thresholds";
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
+}
+
+TEST(IoOveruseConfigsTest, TestFailsUpdateOnDuplicateConfigsForSameComponent) {
+ IoOveruseConfigs ioOveruseConfigs;
+ EXPECT_FALSE(ioOveruseConfigs.update({sampleThirdPartyConfig(), sampleThirdPartyConfig()}).ok())
+ << "Should error on duplicate configs for the same component";
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
+}
+
+TEST(IoOveruseConfigsTest, TestFailsUpdateOnNoIoOveruseConfiguration) {
+ ResourceOveruseConfiguration resConfig;
+ resConfig.componentType = ComponentType::THIRD_PARTY;
+
+ IoOveruseConfigs ioOveruseConfigs;
+ EXPECT_FALSE(ioOveruseConfigs.update({resConfig}).ok())
+ << "Should error on no I/O overuse configuration";
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
+}
+
+TEST(IoOveruseConfigsTest, TestFailsUpdateOnMultipleIoOveruseConfigurations) {
+ IoOveruseConfiguration ioConfig;
+ ioConfig.componentLevelThresholds =
+ toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 100, 200, 300);
+
+ ResourceOveruseConfiguration resConfig;
+ resConfig.componentType = ComponentType::THIRD_PARTY;
+ ResourceSpecificConfiguration resourceSpecificConfig;
+ resourceSpecificConfig.set<ResourceSpecificConfiguration::ioOveruseConfiguration>(ioConfig);
+ resConfig.resourceSpecificConfigurations.push_back(resourceSpecificConfig);
+ resConfig.resourceSpecificConfigurations.push_back(resourceSpecificConfig);
+
+ IoOveruseConfigs ioOveruseConfigs;
+ EXPECT_FALSE(ioOveruseConfigs.update({resConfig}).ok())
+ << "Should error on multiple I/O overuse configuration";
+
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, IsEmpty());
}
TEST(IoOveruseConfigsTest, TestIgnoresNonUpdatableConfigsBySystemComponent) {
- IoOveruseConfiguration updateConfig;
- updateConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 200, 100, 500);
- updateConfig.packageSpecificThresholds = {toPerStateIoOveruseThreshold("systemPackageA", 600,
- 400, 1000),
- toPerStateIoOveruseThreshold("systemPackageB", 1200,
- 800, 1500)};
- updateConfig.safeToKillPackages = toString16Vector({"systemPackageA"});
- updateConfig.vendorPackagePrefixes = toString16Vector({"vendorPackage"});
- updateConfig.categorySpecificThresholds = {toPerStateIoOveruseThreshold("MAPS", 600, 400, 1000),
- toPerStateIoOveruseThreshold("MEDIA", 1200, 800,
- 1500)};
- updateConfig.systemWideThresholds = {toIoOveruseAlertThreshold(5, 200),
- toIoOveruseAlertThreshold(30, 40000)};
+ auto systemIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 200, 100, 500),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("systemPackageA", 600, 400, 1000),
+ toPerStateIoOveruseThreshold("systemPackageB", 1200, 800, 1500)},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", 700, 900, 1300),
+ toPerStateIoOveruseThreshold("MEDIA", 1800, 1900, 2100)},
+ /*systemWide=*/
+ {toIoOveruseAlertThreshold(5, 200), toIoOveruseAlertThreshold(30, 40000)});
+ auto systemResourceConfig =
+ constructResourceOveruseConfig(ComponentType::SYSTEM, /*safeToKill=*/{"systemPackageA"},
+ /*vendorPrefixes=*/{"vendorPackage"},
+ /*packageMetadata=*/{}, systemIoConfig);
IoOveruseConfigs ioOveruseConfigs;
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::SYSTEM, updateConfig));
+ ASSERT_RESULT_OK(ioOveruseConfigs.update({systemResourceConfig}));
- std::vector<PackageConfigTest> packageConfigTests =
- {{.packageInfo = constructPackageInfo("systemMapsPackage", ComponentType::SYSTEM,
- ApplicationCategoryType::MAPS),
- .expectedThreshold = updateConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("systemPackageA", ComponentType::SYSTEM),
- .expectedThreshold = updateConfig.packageSpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("systemPackageB", ComponentType::SYSTEM,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold = updateConfig.packageSpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = false}};
+ // Drop fields that aren't updatable by system component.
+ systemIoConfig.categorySpecificThresholds.clear();
+ systemResourceConfig =
+ constructResourceOveruseConfig(ComponentType::SYSTEM, /*safeToKill=*/{"systemPackageA"},
+ /*vendorPrefixes=*/{}, /*packageMetadata=*/{},
+ systemIoConfig);
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ std::vector<ResourceOveruseConfiguration> expected = {systemResourceConfig};
- EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(),
- UnorderedElementsAre(updateConfig.systemWideThresholds[0],
- updateConfig.systemWideThresholds[1]));
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
- EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(), IsEmpty())
- << "System component config shouldn't update vendor package prefixes. Only vendor "
- << "component config should update this";
+ EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ << "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
TEST(IoOveruseConfigsTest, TestIgnoresNonUpdatableConfigsByVendorComponent) {
- IoOveruseConfiguration updateConfig;
- updateConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::VENDOR, 100, 50, 900);
- updateConfig.packageSpecificThresholds = {toPerStateIoOveruseThreshold("vendorPackageA", 800,
- 300, 500),
- toPerStateIoOveruseThreshold("systemPackageB", 1600,
- 600, 1000)};
- updateConfig.safeToKillPackages = toString16Vector({"vendorPackageA"});
- updateConfig.vendorPackagePrefixes = toString16Vector({"vendorPackage"});
- updateConfig.categorySpecificThresholds = {toPerStateIoOveruseThreshold("MAPS", 600, 400, 1000),
- toPerStateIoOveruseThreshold("MEDIA", 1200, 800,
- 1500)};
- updateConfig.systemWideThresholds = {toIoOveruseAlertThreshold(5, 200),
- toIoOveruseAlertThreshold(30, 40000)};
+ auto vendorIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::VENDOR, 100, 50, 900),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("vendorPackageA", 800, 300, 500),
+ toPerStateIoOveruseThreshold("vendorPkgB", 1600, 600, 1000)},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", 700, 900, 1300),
+ toPerStateIoOveruseThreshold("MEDIA", 1800, 1900, 2100)},
+ /*systemWide=*/
+ {toIoOveruseAlertThreshold(5, 200), toIoOveruseAlertThreshold(30, 40000)});
+ auto vendorResourceConfig =
+ constructResourceOveruseConfig(ComponentType::VENDOR,
+ /*safeToKill=*/
+ {"vendorPackageA"},
+ /*vendorPrefixes=*/{"vendorPackage", "vendorPkg"},
+ /*packageMetadata=*/{}, vendorIoConfig);
IoOveruseConfigs ioOveruseConfigs;
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::VENDOR, updateConfig));
+ ASSERT_RESULT_OK(ioOveruseConfigs.update({vendorResourceConfig}));
- std::vector<PackageConfigTest> packageConfigTests =
- {{.packageInfo = constructPackageInfo("vendorPackageGeneric", ComponentType::VENDOR),
- .expectedThreshold = updateConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorPackageA", ComponentType::VENDOR),
- .expectedThreshold = updateConfig.packageSpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("systemPackageB", ComponentType::VENDOR,
- ApplicationCategoryType::MEDIA),
- .expectedThreshold = updateConfig.packageSpecificThresholds[1].perStateWriteBytes,
- .expectedIsSafeToKill = false},
- {.packageInfo = constructPackageInfo("vendorMapsPackage", ComponentType::VENDOR,
- ApplicationCategoryType::MAPS),
- .expectedThreshold = updateConfig.categorySpecificThresholds[0].perStateWriteBytes,
- .expectedIsSafeToKill = false}};
+ // Drop fields that aren't updatable by vendor component.
+ vendorIoConfig.systemWideThresholds.clear();
+ vendorResourceConfig =
+ constructResourceOveruseConfig(ComponentType::VENDOR,
+ /*safeToKill=*/
+ {"vendorPackageA"},
+ /*vendorPrefixes=*/{"vendorPackage", "vendorPkg"},
+ /*packageMetadata=*/{}, vendorIoConfig);
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ std::vector<ResourceOveruseConfiguration> expected = {vendorResourceConfig};
- EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(), IsEmpty())
- << "Vendor component config shouldn't update system wide alert thresholds. Only system "
- << "component config should update this";
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
- EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(),
- UnorderedElementsAre("vendorPackage", "systemPackageB"));
+ EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ << "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
TEST(IoOveruseConfigsTest, TestIgnoresNonUpdatableConfigsByThirdPartyComponent) {
- IoOveruseConfiguration updateConfig;
- updateConfig.componentLevelThresholds =
- toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 300, 150, 1900);
- updateConfig.packageSpecificThresholds = {toPerStateIoOveruseThreshold("vendorPackageA", 800,
- 300, 500),
- toPerStateIoOveruseThreshold("systemPackageB", 1600,
- 600, 1000)};
- updateConfig.safeToKillPackages = toString16Vector({"vendorPackageA", "systemPackageB"});
- updateConfig.vendorPackagePrefixes = toString16Vector({"vendorPackage"});
- updateConfig.categorySpecificThresholds = {toPerStateIoOveruseThreshold("MAPS", 600, 400, 1000),
- toPerStateIoOveruseThreshold("MEDIA", 1200, 800,
- 1500)};
- updateConfig.systemWideThresholds = {toIoOveruseAlertThreshold(5, 200),
- toIoOveruseAlertThreshold(30, 40000)};
+ auto thirdPartyIoConfig = constructIoOveruseConfig(
+ /*componentLevel=*/
+ toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 300, 150, 1900),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("vendorPackageA", 800, 300, 500),
+ toPerStateIoOveruseThreshold("systemPackageB", 1600, 600, 1000)},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", 700, 900, 1300),
+ toPerStateIoOveruseThreshold("MEDIA", 1800, 1900, 2100)},
+ /*systemWide=*/
+ {toIoOveruseAlertThreshold(5, 200), toIoOveruseAlertThreshold(30, 40000)});
+ auto thirdPartyResourceConfig =
+ constructResourceOveruseConfig(ComponentType::THIRD_PARTY,
+ /*safeToKill=*/{"vendorPackageA", "systemPackageB"},
+ /*vendorPrefixes=*/{"vendorPackage"},
+ /*packageMetadata=*/{}, thirdPartyIoConfig);
IoOveruseConfigs ioOveruseConfigs;
- ASSERT_RESULT_OK(ioOveruseConfigs.update(ComponentType::THIRD_PARTY, updateConfig));
+ ASSERT_RESULT_OK(ioOveruseConfigs.update({thirdPartyResourceConfig}));
- std::vector<PackageConfigTest> packageConfigTests =
- {{.packageInfo = constructPackageInfo("vendorPackageA", ComponentType::THIRD_PARTY,
- ApplicationCategoryType::MAPS),
- .expectedThreshold = updateConfig.componentLevelThresholds.perStateWriteBytes,
- .expectedIsSafeToKill = true},
- {.packageInfo = constructPackageInfo("systemPackageB", ComponentType::SYSTEM,
- ApplicationCategoryType::MAPS),
- .expectedThreshold = defaultThreshold().perStateWriteBytes,
- .expectedIsSafeToKill = false}};
+ // Drop fields that aren't updatable by third-party component.
+ thirdPartyIoConfig.packageSpecificThresholds.clear();
+ thirdPartyIoConfig.categorySpecificThresholds.clear();
+ thirdPartyIoConfig.systemWideThresholds.clear();
+ thirdPartyResourceConfig =
+ constructResourceOveruseConfig(ComponentType::THIRD_PARTY,
+ /*safeToKill=*/{}, /*vendorPrefixes=*/{},
+ /*packageMetadata=*/{}, thirdPartyIoConfig);
- for (const auto& test : packageConfigTests) {
- const auto actualThreshold = ioOveruseConfigs.fetchThreshold(test.packageInfo);
- EXPECT_THAT(actualThreshold, test.expectedThreshold)
- << test.packageInfo.toString()
- << ": \nExpected threshold: " << test.expectedThreshold.toString()
- << "\nActual threshold: " << actualThreshold.toString();
- EXPECT_THAT(ioOveruseConfigs.isSafeToKill(test.packageInfo), test.expectedIsSafeToKill)
- << test.packageInfo.toString() << ": doesn't match expected safe-to-kill value";
- }
+ std::vector<ResourceOveruseConfiguration> expected = {thirdPartyResourceConfig};
- EXPECT_THAT(ioOveruseConfigs.systemWideAlertThresholds(), IsEmpty())
- << "Third-party component config shouldn't update system wide alert thresholds. "
- << "Only system component config should update this";
- EXPECT_THAT(ioOveruseConfigs.vendorPackagePrefixes(), IsEmpty())
- << "Third-party component config shouldn't update vendor package prefixes. Only vendor "
- << "component config should update this";
+ std::vector<ResourceOveruseConfiguration> actual;
+ ioOveruseConfigs.get(&actual);
+
+ EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ << "Expected: " << toString(expected) << "Actual:" << toString(actual);
+}
+
+TEST(IoOveruseConfigsTest, TestFetchThresholdForSystemPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ auto actual = ioOveruseConfigs->fetchThreshold(
+ constructPackageInfo("systemPackageGeneric", ComponentType::SYSTEM));
+
+ EXPECT_THAT(actual, SYSTEM_COMPONENT_LEVEL_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(
+ constructPackageInfo("systemPackageA", ComponentType::SYSTEM));
+
+ EXPECT_THAT(actual, SYSTEM_PACKAGE_A_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(constructPackageInfo("systemPackageB",
+ ComponentType::SYSTEM,
+ ApplicationCategoryType::MEDIA));
+
+ // Package specific thresholds get priority over media category thresholds.
+ EXPECT_THAT(actual, SYSTEM_PACKAGE_B_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(constructPackageInfo("systemPackageC",
+ ComponentType::SYSTEM,
+ ApplicationCategoryType::MEDIA));
+
+ // Media category thresholds as there is no package specific thresholds.
+ EXPECT_THAT(actual, MEDIA_THRESHOLDS);
+}
+
+TEST(IoOveruseConfigsTest, TestFetchThresholdForVendorPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ auto actual = ioOveruseConfigs->fetchThreshold(
+ constructPackageInfo("vendorPackageGeneric", ComponentType::VENDOR));
+
+ EXPECT_THAT(actual, VENDOR_COMPONENT_LEVEL_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(
+ constructPackageInfo("vendorPkgB", ComponentType::VENDOR));
+
+ EXPECT_THAT(actual, VENDOR_PKG_B_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(constructPackageInfo("vendorPackageC",
+ ComponentType::VENDOR,
+ ApplicationCategoryType::MAPS));
+
+ // Maps category thresholds as there is no package specific thresholds.
+ EXPECT_THAT(actual, MAPS_THRESHOLDS);
+}
+
+TEST(IoOveruseConfigsTest, TestFetchThresholdForThirdPartyPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ auto actual = ioOveruseConfigs->fetchThreshold(
+ constructPackageInfo("vendorPackageGenericImpostor", ComponentType::THIRD_PARTY));
+
+ EXPECT_THAT(actual, THIRD_PARTY_COMPONENT_LEVEL_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(constructPackageInfo("3pMapsPackage",
+ ComponentType::THIRD_PARTY,
+ ApplicationCategoryType::MAPS));
+
+ EXPECT_THAT(actual, MAPS_THRESHOLDS);
+
+ actual = ioOveruseConfigs->fetchThreshold(constructPackageInfo("3pMediaPackage",
+ ComponentType::THIRD_PARTY,
+ ApplicationCategoryType::MEDIA));
+
+ EXPECT_THAT(actual, MEDIA_THRESHOLDS);
+}
+
+TEST(IoOveruseConfigsTest, TestIsSafeToKillSystemPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+ EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("systemPackageGeneric", ComponentType::SYSTEM)));
+
+ EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("systemPackageA", ComponentType::SYSTEM)));
+}
+
+TEST(IoOveruseConfigsTest, TestIsSafeToKillVendorPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+ EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("vendorPackageGeneric", ComponentType::VENDOR)));
+
+ EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("vendorPackageA", ComponentType::VENDOR)));
+}
+
+TEST(IoOveruseConfigsTest, TestIsSafeToKillThirdPartyPackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+ EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("vendorPackageGenericImpostor", ComponentType::THIRD_PARTY)));
+
+ EXPECT_TRUE(ioOveruseConfigs->isSafeToKill(
+ constructPackageInfo("3pMapsPackage", ComponentType::THIRD_PARTY,
+ ApplicationCategoryType::MAPS)));
+}
+
+TEST(IoOveruseConfigsTest, TestIsSafeToKillNativePackages) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ PackageInfo packageInfo;
+ packageInfo.packageIdentifier.name = "native package";
+ packageInfo.uidType = UidType::NATIVE;
+ packageInfo.componentType = ComponentType::SYSTEM;
+
+ EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo));
+
+ packageInfo.componentType = ComponentType::VENDOR;
+
+ EXPECT_FALSE(ioOveruseConfigs->isSafeToKill(packageInfo));
+}
+
+TEST(IoOveruseConfigsTest, TestSystemWideAlertThresholds) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ EXPECT_THAT(ioOveruseConfigs->systemWideAlertThresholds(),
+ UnorderedElementsAreArray(ALERT_THRESHOLDS));
+}
+
+TEST(IoOveruseConfigsTest, TestVendorPackagePrefixes) {
+ const auto ioOveruseConfigs = sampleIoOveruseConfigs();
+
+ EXPECT_THAT(ioOveruseConfigs->vendorPackagePrefixes(),
+ UnorderedElementsAre("vendorPackage", "vendorPkgB"));
+}
+
+TEST(IoOveruseConfigsTest, TestPackagesToAppCategoriesWithSystemConfig) {
+ IoOveruseConfigs ioOveruseConfigs;
+ const auto resourceOveruseConfig = sampleSystemConfig();
+
+ ASSERT_RESULT_OK(ioOveruseConfigs.update({resourceOveruseConfig}));
+
+ EXPECT_THAT(ioOveruseConfigs.packagesToAppCategories(),
+ UnorderedElementsAreArray(
+ toPackageToAppCategoryMappings(resourceOveruseConfig.packageMetadata)));
+}
+
+TEST(IoOveruseConfigsTest, TestPackagesToAppCategoriesWithVendorConfig) {
+ IoOveruseConfigs ioOveruseConfigs;
+ const auto resourceOveruseConfig = sampleVendorConfig();
+
+ ASSERT_RESULT_OK(ioOveruseConfigs.update({resourceOveruseConfig}));
+
+ EXPECT_THAT(ioOveruseConfigs.packagesToAppCategories(),
+ UnorderedElementsAreArray(
+ toPackageToAppCategoryMappings(resourceOveruseConfig.packageMetadata)));
}
} // namespace watchdog
diff --git a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
index 1f28704..4ee94eb 100644
--- a/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseMonitorTest.cpp
@@ -31,12 +31,12 @@
namespace watchdog {
constexpr size_t kTestMonitorBufferSize = 3;
+constexpr uint64_t KTestMinSyncWrittenBytes = 5'000;
constexpr double kTestIoOveruseWarnPercentage = 80;
constexpr std::chrono::seconds kTestMonitorInterval = 5s;
using ::android::IPCThreadState;
using ::android::RefBase;
-using ::android::String16;
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::IoOveruseAlertThreshold;
@@ -69,7 +69,7 @@
PackageIdentifier constructPackageIdentifier(const char* packageName, const int32_t uid) {
PackageIdentifier packageIdentifier;
- packageIdentifier.name = String16(String8(packageName));
+ packageIdentifier.name = packageName;
packageIdentifier.uid = uid;
return packageIdentifier;
}
@@ -171,10 +171,11 @@
mIoOveruseMonitor(ioOveruseMonitor) {}
Result<void> init(const sp<IIoOveruseConfigs>& ioOveruseConfigs,
- const sp<IPackageInfoResolverInterface>& packageInfoResolver) {
+ const sp<IPackageInfoResolver>& packageInfoResolver) {
if (const auto result = mIoOveruseMonitor->init(); !result.ok()) {
return result;
}
+ mIoOveruseMonitor->mMinSyncWrittenBytes = KTestMinSyncWrittenBytes;
mIoOveruseMonitor->mPeriodicMonitorBufferSize = kTestMonitorBufferSize;
mIoOveruseMonitor->mIoOveruseWarnPercentage = kTestIoOveruseWarnPercentage;
mIoOveruseMonitor->mIoOveruseConfigs = ioOveruseConfigs;
@@ -220,23 +221,22 @@
};
TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollection) {
- std::unordered_map<uid_t, PackageInfo> packageInfoMapping = {
- {1001000,
- constructPackageInfo(
- /*packageName=*/"system.daemon", /*uid=*/1001000, UidType::NATIVE)},
- {1112345,
- constructPackageInfo(
- /*packageName=*/"com.android.google.package", /*uid=*/1112345,
- UidType::APPLICATION)},
- {1212345,
- constructPackageInfo(
- /*packageName=*/"com.android.google.package", /*uid=*/1212345,
- UidType::APPLICATION)},
- {1113999,
- constructPackageInfo(
- /*packageName=*/"com.android.google.package", /*uid=*/1113999,
- UidType::APPLICATION)},
- };
+ std::unordered_map<uid_t, PackageInfo> packageInfoMapping =
+ {{1001000,
+ constructPackageInfo(
+ /*packageName=*/"system.daemon", /*uid=*/1001000, UidType::NATIVE)},
+ {1112345,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1112345,
+ UidType::APPLICATION)},
+ {1212345,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1212345,
+ UidType::APPLICATION)},
+ {1113999,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1113999,
+ UidType::APPLICATION)}};
ON_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
.WillByDefault(Return(packageInfoMapping));
mMockIoOveruseConfigs->injectPackageConfigs({
@@ -272,24 +272,25 @@
ASSERT_RESULT_OK(
mIoOveruseMonitor->onPeriodicCollection(currentTime, mockUidIoStats, nullptr, nullptr));
- std::vector<PackageIoOveruseStats> expectedIoOveruseStats = {
- constructPackageIoOveruseStats(/*uid*=*/1001000, /*shouldNotify=*/false,
- /*isKillable=*/false, /*remaining=*/
- constructPerStateBytes(10'000, 20'000, 100'000),
- /*written=*/constructPerStateBytes(70'000, 20'000, 0),
- /*totalOveruses=*/0, startTime, durationInSeconds),
- constructPackageIoOveruseStats(/*uid*=*/1112345, /*shouldNotify=*/false,
- /*isKillable=*/true, /*remaining=*/
- constructPerStateBytes(35'000, 15'000, 100'000),
- /*written=*/constructPerStateBytes(35'000, 15'000, 0),
- /*totalOveruses=*/0, startTime, durationInSeconds),
- // Exceeds threshold.
- constructPackageIoOveruseStats(/*uid*=*/1212345, /*shouldNotify=*/true,
- /*isKillable=*/true,
- /*remaining=*/constructPerStateBytes(0, 10'000, 100'000),
- /*written=*/constructPerStateBytes(70'000, 20'000, 0),
- /*totalOveruses=*/1, startTime, durationInSeconds),
- };
+
+ std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
+ {constructPackageIoOveruseStats(/*uid*=*/1001000, /*shouldNotify=*/false,
+ /*isKillable=*/false, /*remaining=*/
+ constructPerStateBytes(10'000, 20'000, 100'000),
+ /*written=*/constructPerStateBytes(70'000, 20'000, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(/*uid*=*/1112345, /*shouldNotify=*/false,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(35'000, 15'000, 100'000),
+ /*written=*/constructPerStateBytes(35'000, 15'000, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ // Exceeds threshold.
+ constructPackageIoOveruseStats(/*uid*=*/1212345, /*shouldNotify=*/true,
+ /*isKillable=*/true,
+ /*remaining=*/
+ constructPerStateBytes(0, 10'000, 100'000),
+ /*written=*/constructPerStateBytes(70'000, 20'000, 0),
+ /*totalOveruses=*/1, startTime, durationInSeconds)};
EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
<< "Expected: " << toString(expectedIoOveruseStats)
<< "\nActual: " << toString(actualIoOveruseStats);
@@ -384,15 +385,171 @@
<< "\nActual: " << toString(actualIoOveruseStats);
}
+TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithZeroWriteBytes) {
+ sp<MockUidIoStats> mockUidIoStats = new MockUidIoStats();
+ mockUidIoStats->expectDeltaStats(
+ {{1001000, IoUsage(10, 0, /*fgWrBytes=*/0, /*bgWrBytes=*/0, 1, 0)},
+ {1112345, IoUsage(0, 20, /*fgWrBytes=*/0, /*bgWrBytes=*/0, 0, 0)},
+ {1212345, IoUsage(0, 00, /*fgWrBytes=*/0, /*bgWrBytes=*/0, 0, 1)}});
+
+ EXPECT_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_)).Times(0);
+ EXPECT_CALL(*mMockIoOveruseConfigs, fetchThreshold(_)).Times(0);
+ EXPECT_CALL(*mMockIoOveruseConfigs, isSafeToKill(_)).Times(0);
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_)).Times(0);
+
+ ASSERT_RESULT_OK(
+ mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
+ std::chrono::system_clock::now()),
+ mockUidIoStats, nullptr, nullptr));
+}
+
+TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithSmallWrittenBytes) {
+ std::unordered_map<uid_t, PackageInfo> packageInfoMapping =
+ {{1001000,
+ constructPackageInfo(
+ /*packageName=*/"system.daemon", /*uid=*/1001000, UidType::NATIVE)},
+ {1112345,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1112345,
+ UidType::APPLICATION)},
+ {1212345,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1212345,
+ UidType::APPLICATION)},
+ {1312345,
+ constructPackageInfo(
+ /*packageName=*/"com.android.google.package", /*uid=*/1312345,
+ UidType::APPLICATION)}};
+ EXPECT_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
+ .WillRepeatedly(Return(packageInfoMapping));
+ mMockIoOveruseConfigs->injectPackageConfigs(
+ {{"system.daemon",
+ {constructPerStateBytes(/*fgBytes=*/80'000, /*bgBytes=*/40'000, /*gmBytes=*/100'000),
+ /*isSafeToKill=*/false}},
+ {"com.android.google.package",
+ {constructPerStateBytes(/*fgBytes=*/70'000, /*bgBytes=*/30'000, /*gmBytes=*/100'000),
+ /*isSafeToKill=*/true}}});
+
+ sp<MockUidIoStats> mockUidIoStats = new MockUidIoStats();
+ /*
+ * UID 1212345 current written bytes < |KTestMinSyncWrittenBytes| so the UID's stats are not
+ * synced.
+ */
+ mockUidIoStats->expectDeltaStats(
+ {{1001000, IoUsage(10, 0, /*fgWrBytes=*/59'200, /*bgWrBytes=*/0, 1, 0)},
+ {1112345, IoUsage(0, 20, /*fgWrBytes=*/0, /*bgWrBytes=*/25'200, 0, 0)},
+ {1212345, IoUsage(0, 00, /*fgWrBytes=*/300, /*bgWrBytes=*/600, 0, 1)},
+ {1312345, IoUsage(0, 00, /*fgWrBytes=*/51'200, /*bgWrBytes=*/0, 0, 1)}});
+
+ std::vector<PackageIoOveruseStats> actualIoOveruseStats;
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+ .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+
+ time_t currentTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
+ const auto [startTime, durationInSeconds] = calculateStartAndDuration(currentTime);
+
+ ASSERT_RESULT_OK(
+ mIoOveruseMonitor->onPeriodicCollection(currentTime, mockUidIoStats, nullptr, nullptr));
+
+ std::vector<PackageIoOveruseStats> expectedIoOveruseStats =
+ {constructPackageIoOveruseStats(/*uid*=*/1001000, /*shouldNotify=*/false,
+ /*isKillable=*/false, /*remaining=*/
+ constructPerStateBytes(20'800, 40'000, 100'000),
+ /*written=*/
+ constructPerStateBytes(59'200, 0, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(/*uid*=*/1112345, /*shouldNotify=*/true,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(70'000, 4'800, 100'000),
+ /*written=*/constructPerStateBytes(0, 25'200, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(/*uid*=*/1312345, /*shouldNotify=*/false,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(18'800, 30'000, 100'000),
+ /*written=*/constructPerStateBytes(51'200, 0, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds)};
+
+ EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
+ << "Expected: " << toString(expectedIoOveruseStats)
+ << "\nActual: " << toString(actualIoOveruseStats);
+
+ actualIoOveruseStats.clear();
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_))
+ .WillOnce(DoAll(SaveArg<0>(&actualIoOveruseStats), Return(Status::ok())));
+
+ /*
+ * UID 1001000 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds warn threshold
+ * but not killable so the UID's stats are not synced.
+ * UID 1112345 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds threshold so
+ * the UID's stats are synced.
+ * UID 1212345 current written bytes is < |kTestMinSyncWrittenBytes| but total written bytes
+ * since last synced > |kTestMinSyncWrittenBytes| so the UID's stats are synced.
+ * UID 1312345 current written bytes is < |kTestMinSyncWrittenBytes| but exceeds warn threshold
+ * and killable so the UID's stat are synced.
+ */
+ mockUidIoStats->expectDeltaStats(
+ {{1001000,
+ IoUsage(10, 0, /*fgWrBytes=*/KTestMinSyncWrittenBytes - 100, /*bgWrBytes=*/0, 1, 0)},
+ {1112345,
+ IoUsage(0, 20, /*fgWrBytes=*/0, /*bgWrBytes=*/KTestMinSyncWrittenBytes - 100, 0, 0)},
+ {1212345,
+ IoUsage(0, 00, /*fgWrBytes=*/KTestMinSyncWrittenBytes - 300, /*bgWrBytes=*/0, 0, 1)},
+ {1312345,
+ IoUsage(0, 00, /*fgWrBytes=*/KTestMinSyncWrittenBytes - 100, /*bgWrBytes=*/0, 0,
+ 1)}});
+
+ ASSERT_RESULT_OK(
+ mIoOveruseMonitor->onPeriodicCollection(currentTime, mockUidIoStats, nullptr, nullptr));
+
+ expectedIoOveruseStats =
+ {constructPackageIoOveruseStats(/*uid*=*/1112345, /*shouldNotify=*/true,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(70'000, 0, 100'000),
+ /*written=*/constructPerStateBytes(0, 30'100, 0),
+ /*totalOveruses=*/1, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(/*uid*=*/1212345, /*shouldNotify=*/false,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(65'000, 29'400, 100'000),
+ /*written=*/constructPerStateBytes(5'000, 600, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds),
+ constructPackageIoOveruseStats(/*uid*=*/1312345, /*shouldNotify=*/true,
+ /*isKillable=*/true, /*remaining=*/
+ constructPerStateBytes(13'900, 30'000, 100'000),
+ /*written=*/constructPerStateBytes(56'100, 0, 0),
+ /*totalOveruses=*/0, startTime, durationInSeconds)};
+ EXPECT_THAT(actualIoOveruseStats, UnorderedElementsAreArray(expectedIoOveruseStats))
+ << "Expected: " << toString(expectedIoOveruseStats)
+ << "\nActual: " << toString(actualIoOveruseStats);
+}
+
+TEST_F(IoOveruseMonitorTest, TestOnPeriodicCollectionWithNoPackageInfo) {
+ sp<MockUidIoStats> mockUidIoStats = new MockUidIoStats();
+ mockUidIoStats->expectDeltaStats(
+ {{1001000, IoUsage(0, 0, /*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000, 0, 0)},
+ {1112345, IoUsage(0, 0, /*fgWrBytes=*/35'000, /*bgWrBytes=*/15'000, 0, 0)},
+ {1212345, IoUsage(0, 0, /*fgWrBytes=*/70'000, /*bgWrBytes=*/20'000, 0, 0)}});
+
+ ON_CALL(*mMockPackageInfoResolver, getPackageInfosForUids(_))
+ .WillByDefault(Return(std::unordered_map<uid_t, PackageInfo>{}));
+
+ EXPECT_CALL(*mMockIoOveruseConfigs, fetchThreshold(_)).Times(0);
+ EXPECT_CALL(*mMockIoOveruseConfigs, isSafeToKill(_)).Times(0);
+ EXPECT_CALL(*mMockWatchdogServiceHelper, latestIoOveruseStats(_)).Times(0);
+
+ ASSERT_RESULT_OK(
+ mIoOveruseMonitor->onPeriodicCollection(std::chrono::system_clock::to_time_t(
+ std::chrono::system_clock::now()),
+ mockUidIoStats, nullptr, nullptr));
+}
+
TEST_F(IoOveruseMonitorTest, TestOnPeriodicMonitor) {
- IIoOveruseConfigs::IoOveruseAlertThresholdSet alertThresholds = {
- toIoOveruseAlertThreshold(
- /*durationInSeconds=*/10, /*writtenBytesPerSecond=*/15'360),
- toIoOveruseAlertThreshold(
- /*durationInSeconds=*/17, /*writtenBytesPerSecond=*/10'240),
- toIoOveruseAlertThreshold(
- /*durationInSeconds=*/23, /*writtenBytesPerSecond=*/7'168),
- };
+ IIoOveruseConfigs::IoOveruseAlertThresholdSet alertThresholds =
+ {toIoOveruseAlertThreshold(
+ /*durationInSeconds=*/10, /*writtenBytesPerSecond=*/15'360),
+ toIoOveruseAlertThreshold(
+ /*durationInSeconds=*/17, /*writtenBytesPerSecond=*/10'240),
+ toIoOveruseAlertThreshold(
+ /*durationInSeconds=*/23, /*writtenBytesPerSecond=*/7'168)};
ON_CALL(*mMockIoOveruseConfigs, systemWideAlertThresholds())
.WillByDefault(ReturnRef(alertThresholds));
diff --git a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
index 8ea4ba3..c8f1614 100644
--- a/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
+++ b/cpp/watchdog/server/tests/MockCarWatchdogServiceForSystem.h
@@ -24,7 +24,6 @@
#include <binder/Status.h>
#include <gmock/gmock.h>
#include <utils/RefBase.h>
-#include <utils/String16.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -45,7 +44,7 @@
(int32_t, android::automotive::watchdog::internal::TimeoutLength), (override));
MOCK_METHOD(android::binder::Status, prepareProcessTermination, (), (override));
MOCK_METHOD(android::binder::Status, getPackageInfosForUids,
- (const std::vector<int32_t>&, const std::vector<android::String16>&,
+ (const std::vector<int32_t>&, const std::vector<std::string>&,
std::vector<android::automotive::watchdog::internal::PackageInfo>*),
(override));
MOCK_METHOD(
diff --git a/cpp/watchdog/server/tests/MockDataProcessor.h b/cpp/watchdog/server/tests/MockDataProcessor.h
index e120ff7..34a572e 100644
--- a/cpp/watchdog/server/tests/MockDataProcessor.h
+++ b/cpp/watchdog/server/tests/MockDataProcessor.h
@@ -28,7 +28,7 @@
class MockDataProcessor : virtual public IDataProcessorInterface {
public:
MockDataProcessor() {
- ON_CALL(*this, name()).WillByDefault(::testing::Return("MockedDataProcessor"));
+ EXPECT_CALL(*this, name()).WillRepeatedly(::testing::Return("MockedDataProcessor"));
}
MOCK_METHOD(std::string, name, (), (override));
MOCK_METHOD(android::base::Result<void>, init, (), (override));
diff --git a/cpp/watchdog/server/tests/MockIoOveruseConfigs.h b/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
index 9d4091d..cc88c1d 100644
--- a/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
+++ b/cpp/watchdog/server/tests/MockIoOveruseConfigs.h
@@ -21,9 +21,10 @@
#include <android-base/result.h>
#include <android/automotive/watchdog/PerStateBytes.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
#include <android/automotive/watchdog/internal/ComponentType.h>
-#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
#include <android/automotive/watchdog/internal/PackageInfo.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
#include <gmock/gmock.h>
namespace android {
@@ -35,12 +36,22 @@
MockIoOveruseConfigs() {}
~MockIoOveruseConfigs() {}
MOCK_METHOD(android::base::Result<void>, update,
- (const android::automotive::watchdog::internal::ComponentType,
- const android::automotive::watchdog::internal::IoOveruseConfiguration&),
+ (const std::vector<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
(override));
+ MOCK_METHOD(
+ void, get,
+ (std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
+ (override));
+
MOCK_METHOD((const std::unordered_set<std::string>&), vendorPackagePrefixes, (), (override));
+ MOCK_METHOD((const std::unordered_map<
+ std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>&),
+ packagesToAppCategories, (), (override));
+
MOCK_METHOD(PerStateBytes, fetchThreshold,
(const android::automotive::watchdog::internal::PackageInfo&), (const, override));
@@ -60,8 +71,7 @@
.WillByDefault([perPackageConfig = perPackageConfig](
const android::automotive::watchdog::internal::PackageInfo&
packageInfo) {
- const std::string packageName =
- std::string(String8(packageInfo.packageIdentifier.name));
+ const std::string packageName = packageInfo.packageIdentifier.name;
if (const auto it = perPackageConfig.find(packageName);
it != perPackageConfig.end()) {
return it->second.threshold;
@@ -72,8 +82,7 @@
.WillByDefault([perPackageConfig = perPackageConfig](
const android::automotive::watchdog::internal::PackageInfo&
packageInfo) {
- const std::string packageName =
- std::string(String8(packageInfo.packageIdentifier.name));
+ const std::string packageName = packageInfo.packageIdentifier.name;
if (const auto it = perPackageConfig.find(packageName);
it != perPackageConfig.end()) {
return it->second.isSafeToKill;
diff --git a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
index d6ca484..cb7d0c5 100644
--- a/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
+++ b/cpp/watchdog/server/tests/MockIoOveruseMonitor.h
@@ -35,11 +35,15 @@
ON_CALL(*this, name()).WillByDefault(::testing::Return("MockIoOveruseMonitor"));
}
~MockIoOveruseMonitor() {}
-
- MOCK_METHOD(android::base::Result<void>, updateIoOveruseConfiguration,
- (android::automotive::watchdog::internal::ComponentType,
- const android::automotive::watchdog::internal::IoOveruseConfiguration&),
+ MOCK_METHOD(bool, isInitialized, (), (override));
+ MOCK_METHOD(android::base::Result<void>, updateResourceOveruseConfigurations,
+ (const std::vector<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>&),
(override));
+ MOCK_METHOD(
+ android::base::Result<void>, getResourceOveruseConfigurations,
+ (std::vector<android::automotive::watchdog::internal::ResourceOveruseConfiguration>*),
+ (override));
MOCK_METHOD(android::base::Result<void>, actionTakenOnIoOveruse,
(const std::vector<
android::automotive::watchdog::internal::PackageResourceOveruseAction>&
diff --git a/cpp/watchdog/server/tests/MockPackageInfoResolver.h b/cpp/watchdog/server/tests/MockPackageInfoResolver.h
index d50a723..e3da3b6 100644
--- a/cpp/watchdog/server/tests/MockPackageInfoResolver.h
+++ b/cpp/watchdog/server/tests/MockPackageInfoResolver.h
@@ -29,7 +29,7 @@
namespace automotive {
namespace watchdog {
-class MockPackageInfoResolver : public IPackageInfoResolverInterface {
+class MockPackageInfoResolver : public IPackageInfoResolver {
public:
MockPackageInfoResolver() {}
MOCK_METHOD(android::base::Result<void>, initWatchdogServiceHelper,
@@ -39,7 +39,11 @@
(const std::vector<uid_t>& uids), (override));
MOCK_METHOD((std::unordered_map<uid_t, android::automotive::watchdog::internal::PackageInfo>),
getPackageInfosForUids, (const std::vector<uid_t>& uids), (override));
- MOCK_METHOD(void, setVendorPackagePrefixes, (const std::unordered_set<std::string>& prefixes),
+ MOCK_METHOD(void, setPackageConfigurations,
+ ((const std::unordered_set<std::string>&),
+ (const std::unordered_map<
+ std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>&)),
(override));
};
diff --git a/cpp/watchdog/server/tests/MockWatchdogPerfService.h b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
index 5d14837..60d165b 100644
--- a/cpp/watchdog/server/tests/MockWatchdogPerfService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogPerfService.h
@@ -36,7 +36,7 @@
MOCK_METHOD(void, terminate, (), (override));
MOCK_METHOD(android::base::Result<void>, onBootFinished, (), (override));
MOCK_METHOD(android::base::Result<void>, onCustomCollection,
- (int fd, const Vector<String16>& args), (override));
+ (int fd, const Vector<android::String16>& args), (override));
MOCK_METHOD(android::base::Result<void>, onDump, (int fd), (override));
};
diff --git a/cpp/watchdog/server/tests/MockWatchdogProcessService.h b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
index 8c35f10..b720d91 100644
--- a/cpp/watchdog/server/tests/MockWatchdogProcessService.h
+++ b/cpp/watchdog/server/tests/MockWatchdogProcessService.h
@@ -40,7 +40,7 @@
class MockWatchdogProcessService : public WatchdogProcessService {
public:
MockWatchdogProcessService() : WatchdogProcessService(nullptr) {}
- MOCK_METHOD(android::base::Result<void>, dump, (int fd, const Vector<String16>& args),
+ MOCK_METHOD(android::base::Result<void>, dump, (int fd, const Vector<android::String16>& args),
(override));
MOCK_METHOD(android::base::Result<void>, registerWatchdogServiceHelper,
(const android::sp<IWatchdogServiceHelperInterface>& helper), (override));
diff --git a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
index a3c126c..f2fe3a6 100644
--- a/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
+++ b/cpp/watchdog/server/tests/PackageInfoResolverTest.cpp
@@ -17,22 +17,22 @@
#include "MockWatchdogServiceHelper.h"
#include "PackageInfoResolver.h"
+#include <android-base/stringprintf.h>
#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
#include <android/automotive/watchdog/internal/ComponentType.h>
#include <android/automotive/watchdog/internal/UidType.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <utils/String16.h>
namespace android {
namespace automotive {
namespace watchdog {
-using ::android::String16;
using ::android::automotive::watchdog::internal::ApplicationCategoryType;
using ::android::automotive::watchdog::internal::ComponentType;
using ::android::automotive::watchdog::internal::PackageInfo;
using ::android::automotive::watchdog::internal::UidType;
+using ::android::base::StringAppendF;
using ::testing::_;
using ::testing::DoAll;
using ::testing::NotNull;
@@ -40,15 +40,20 @@
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
namespace {
+using PackageToAppCategoryMap =
+ std::unordered_map<std::string,
+ android::automotive::watchdog::internal::ApplicationCategoryType>;
+
PackageInfo constructPackageInfo(const char* packageName, int32_t uid, UidType uidType,
ComponentType componentType,
ApplicationCategoryType appCategoryType,
- std::vector<String16> sharedUidPackages = {}) {
+ std::vector<std::string> sharedUidPackages = {}) {
PackageInfo packageInfo;
- packageInfo.packageIdentifier.name = String16(packageName);
+ packageInfo.packageIdentifier.name = packageName;
packageInfo.packageIdentifier.uid = uid;
packageInfo.uidType = uidType;
packageInfo.componentType = componentType;
@@ -57,6 +62,18 @@
return packageInfo;
}
+std::string toString(const std::unordered_map<uid_t, PackageInfo>& mappings) {
+ std::string buffer = "{";
+ for (const auto& [uid, info] : mappings) {
+ if (buffer.size() > 1) {
+ StringAppendF(&buffer, ", ");
+ }
+ StringAppendF(&buffer, "{%d: %s}", uid, info.toString().c_str());
+ }
+ StringAppendF(&buffer, "}");
+ return buffer;
+}
+
} // namespace
namespace internal {
@@ -80,8 +97,10 @@
mPackageInfoResolver->mUidToPackageInfoMapping = mapping;
}
- void setVendorPackagePrefixes(const std::unordered_set<std::string>& prefixes) {
- mPackageInfoResolver->setVendorPackagePrefixes(prefixes);
+ void setPackageConfigurations(const std::unordered_set<std::string>& vendorPackagePrefixes,
+ const PackageToAppCategoryMap& packagesToAppCategories) {
+ mPackageInfoResolver->setPackageConfigurations(vendorPackagePrefixes,
+ packagesToAppCategories);
}
void stubGetpwuid(const std::unordered_map<uid_t, std::string>& nativeUidToPackageNameMapping) {
@@ -133,6 +152,13 @@
TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaGetpwuid) {
internal::PackageInfoResolverPeer peer;
auto packageInfoResolver = PackageInfoResolver::getInstance();
+ PackageToAppCategoryMap packagesToAppCategories = {
+ // These mappings should be ignored for native packages.
+ {"system.package.B", ApplicationCategoryType::MAPS},
+ {"vendor.package.A", ApplicationCategoryType::MEDIA},
+ {"vendor.pkg.maps", ApplicationCategoryType::MAPS},
+ };
+ peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
std::unordered_map<uid_t, PackageInfo> expectedMappings{
{7700,
@@ -142,29 +168,35 @@
constructPackageInfo("vendor.package.A", 5100, UidType::NATIVE, ComponentType::VENDOR,
ApplicationCategoryType::OTHERS)},
{6700,
- constructPackageInfo("vendor.pkg", 6700, UidType::NATIVE, ComponentType::VENDOR,
+ constructPackageInfo("vendor.package.B", 6700, UidType::NATIVE, ComponentType::VENDOR,
+ ApplicationCategoryType::OTHERS)},
+ {9997,
+ constructPackageInfo("vendor.pkg.C", 9997, UidType::NATIVE, ComponentType::VENDOR,
ApplicationCategoryType::OTHERS)},
};
- peer.stubGetpwuid(
- {{7700, "system.package.B"}, {5100, "vendor.package.A"}, {6700, "vendor.pkg"}});
+ peer.stubGetpwuid({{7700, "system.package.B"},
+ {5100, "vendor.package.A"},
+ {6700, "vendor.package.B"},
+ {9997, "vendor.pkg.C"}});
EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
- auto actualMappings = packageInfoResolver->getPackageInfosForUids({7700, 5100, 6700});
+ auto actualMappings = packageInfoResolver->getPackageInfosForUids({7700, 5100, 6700, 9997});
- for (const auto& it : expectedMappings) {
- ASSERT_TRUE(actualMappings.find(it.first) != actualMappings.end())
- << "Mapping not found for UID" << it.first;
- EXPECT_EQ(actualMappings.find(it.first)->second, it.second)
- << "Expected: " << it.second.toString() << "\n"
- << "Actual: " << actualMappings.find(it.first)->second.toString();
- }
+ EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
+ << "Expected: " << toString(expectedMappings)
+ << "\nActual: " << toString(actualMappings);
}
TEST(PackageInfoResolverTest, TestGetPackageInfosForUidsViaWatchdogService) {
internal::PackageInfoResolverPeer peer;
auto packageInfoResolver = PackageInfoResolver::getInstance();
- peer.setVendorPackagePrefixes({"vendor.pkg"});
+ PackageToAppCategoryMap packagesToAppCategories = {
+ // system.package.B is native package so this should be ignored.
+ {"system.package.B", ApplicationCategoryType::MAPS},
+ {"vendor.package.A", ApplicationCategoryType::MEDIA},
+ };
+ peer.setPackageConfigurations({"vendor.pkg"}, packagesToAppCategories);
/*
* Shared UID should be resolved with car watchdog service as well to get the shared packages
* list.
@@ -175,13 +207,13 @@
{6100,
constructPackageInfo("shared:system.package.A", 6100, UidType::NATIVE,
ComponentType::SYSTEM, ApplicationCategoryType::OTHERS,
- {String16("system.pkg.1"), String16("system.pkg.2")})},
+ {"system.pkg.1", "system.pkg.2"})},
{7700,
constructPackageInfo("system.package.B", 7700, UidType::NATIVE, ComponentType::SYSTEM,
ApplicationCategoryType::OTHERS)},
{15100,
- constructPackageInfo("vendor.package.A", 15100, UidType::NATIVE, ComponentType::VENDOR,
- ApplicationCategoryType::OTHERS)},
+ constructPackageInfo("vendor.package.A", 15100, UidType::APPLICATION,
+ ComponentType::VENDOR, ApplicationCategoryType::MEDIA)},
{16700,
constructPackageInfo("vendor.pkg", 16700, UidType::NATIVE, ComponentType::VENDOR,
ApplicationCategoryType::OTHERS)},
@@ -199,30 +231,28 @@
auto actualMappings = packageInfoResolver->getPackageInfosForUids({6100, 7700, 15100, 16700});
- for (const auto& it : expectedMappings) {
- ASSERT_TRUE(actualMappings.find(it.first) != actualMappings.end())
- << "Mapping not found for UID" << it.first;
- EXPECT_EQ(actualMappings.find(it.first)->second, it.second)
- << "Expected: " << it.second.toString() << "\n"
- << "Actual: " << actualMappings.find(it.first)->second.toString();
- }
+ EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
+ << "Expected: " << toString(expectedMappings)
+ << "\nActual: " << toString(actualMappings);
}
TEST(PackageInfoResolverTest, TestResolvesApplicationUidFromLocalCache) {
internal::PackageInfoResolverPeer peer;
auto packageInfoResolver = PackageInfoResolver::getInstance();
- PackageInfo expectedPackageInfo =
- constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
- ApplicationCategoryType::OTHERS);
- peer.injectCacheMapping({{1003456, expectedPackageInfo}});
+ std::unordered_map<uid_t, PackageInfo> expectedMappings{
+ {1003456,
+ constructPackageInfo("vendor.package", 1003456, UidType::NATIVE, ComponentType::SYSTEM,
+ ApplicationCategoryType::OTHERS)}};
+ peer.injectCacheMapping(expectedMappings);
peer.stubGetpwuid({});
EXPECT_CALL(*peer.mockWatchdogServiceHelper, getPackageInfosForUids(_, _, _)).Times(0);
auto actualMappings = packageInfoResolver->getPackageInfosForUids({1003456});
- ASSERT_TRUE(actualMappings.find(1003456) != actualMappings.end());
- EXPECT_EQ(actualMappings.find(1003456)->second, expectedPackageInfo);
+ EXPECT_THAT(actualMappings, UnorderedElementsAreArray(expectedMappings))
+ << "Expected: " << toString(expectedMappings)
+ << "\nActual: " << toString(actualMappings);
}
} // namespace watchdog
diff --git a/cpp/watchdog/server/tests/UidIoStatsTest.cpp b/cpp/watchdog/server/tests/UidIoStatsTest.cpp
index 2326381..6e88ed5 100644
--- a/cpp/watchdog/server/tests/UidIoStatsTest.cpp
+++ b/cpp/watchdog/server/tests/UidIoStatsTest.cpp
@@ -17,6 +17,7 @@
#include "UidIoStats.h"
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <gmock/gmock.h>
#include <unordered_map>
@@ -25,25 +26,37 @@
namespace automotive {
namespace watchdog {
+using ::android::base::StringAppendF;
using ::android::base::WriteStringToFile;
+using ::testing::UnorderedElementsAreArray;
+
+namespace {
+
+std::string toString(std::unordered_map<uid_t, UidIoUsage> usages) {
+ std::string buffer;
+ for (const auto& [uid, usage] : usages) {
+ StringAppendF(&buffer, "{%s}\n", usage.toString().c_str());
+ }
+ return buffer;
+}
+
+} // namespace
TEST(UidIoStatsTest, TestValidStatFile) {
// Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
// fgFsync bgFsync
- constexpr char firstSnapshot[] =
- "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
- "1005678 500 100 30 50 300 400 100 200 45 60\n"
- "1009 0 0 0 0 40000 50000 20000 30000 0 300\n"
- "1001000 4000 3000 2000 1000 400 300 200 100 50 10\n";
- std::unordered_map<uid_t, UidIoUsage> expectedFirstUsage = {
- {1001234,
- {.uid = 1001234,
- .ios = {/*fgRdBytes=*/3000, /*bgRdBytes=*/0, /*fgWrBytes=*/500,
- /*bgWrBytes=*/0, /*fgFsync=*/20, /*bgFsync=*/0}}},
- {1005678, {.uid = 1005678, .ios = {30, 100, 50, 200, 45, 60}}},
- {1009, {.uid = 1009, .ios = {0, 20000, 0, 30000, 0, 300}}},
- {1001000, {.uid = 1001000, .ios = {2000, 200, 1000, 100, 50, 10}}},
- };
+ constexpr char firstSnapshot[] = "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
+ "1005678 500 100 30 50 300 400 100 200 45 60\n"
+ "1009 0 0 0 0 40000 50000 20000 30000 0 300\n"
+ "1001000 4000 3000 2000 1000 400 300 200 100 50 10\n";
+ std::unordered_map<uid_t, UidIoUsage> expectedFirstUsage =
+ {{1001234,
+ {.uid = 1001234,
+ .ios = {/*fgRdBytes=*/3000, /*bgRdBytes=*/0, /*fgWrBytes=*/500,
+ /*bgWrBytes=*/0, /*fgFsync=*/20, /*bgFsync=*/0}}},
+ {1005678, {.uid = 1005678, .ios = {30, 100, 50, 200, 45, 60}}},
+ {1009, {.uid = 1009, .ios = {0, 20000, 0, 30000, 0, 300}}},
+ {1001000, {.uid = 1001000, .ios = {2000, 200, 1000, 100, 50, 10}}}};
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);
ASSERT_TRUE(WriteStringToFile(firstSnapshot, tf.path));
@@ -53,62 +66,38 @@
ASSERT_RESULT_OK(uidIoStats.collect());
const auto& actualFirstUsage = uidIoStats.deltaStats();
- EXPECT_EQ(expectedFirstUsage.size(), actualFirstUsage.size());
+ EXPECT_THAT(actualFirstUsage, UnorderedElementsAreArray(expectedFirstUsage))
+ << "Expected: " << toString(expectedFirstUsage)
+ << "Actual: " << toString(actualFirstUsage);
- for (const auto& it : expectedFirstUsage) {
- if (actualFirstUsage.find(it.first) == actualFirstUsage.end()) {
- ADD_FAILURE() << "Expected uid " << it.first << " not found in the first snapshot";
- }
- const UidIoUsage& expected = it.second;
- const UidIoUsage& actual = actualFirstUsage.at(it.first);
- EXPECT_EQ(expected.uid, actual.uid);
- EXPECT_EQ(expected.ios, actual.ios)
- << "Unexpected I/O usage for uid " << it.first << " in first snapshot.\nExpected:\n"
- << expected.ios.toString() << "\nActual:\n"<< actual.ios.toString();
- }
-
- constexpr char secondSnapshot[] =
- "1001234 10000 2000 7000 950 0 0 0 0 45 0\n"
- "1005678 600 100 40 50 1000 1000 1000 600 50 70\n"
- "1003456 300 500 200 300 0 0 0 0 50 0\n"
- "1001000 400 300 200 100 40 30 20 10 5 1\n";
- std::unordered_map<uid_t, UidIoUsage> expectedSecondUsage = {
- {1001234,
- {.uid = 1001234,
- .ios = {/*fgRdBytes=*/4000, /*bgRdBytes=*/0,
- /*fgWrBytes=*/450, /*bgWrBytes=*/0, /*fgFsync=*/25,
- /*bgFsync=*/0}}},
- {1005678, {.uid = 1005678, .ios = {10, 900, 0, 400, 5, 10}}},
- {1003456, {.uid = 1003456, .ios = {200, 0, 300, 0, 50, 0}}},
- {1001000, {.uid = 1001000, .ios = {0, 0, 0, 0, 0, 0}}},
- };
+ constexpr char secondSnapshot[] = "1001234 10000 2000 7000 950 0 0 0 0 45 0\n"
+ "1005678 600 100 40 50 1000 1000 1000 600 50 70\n"
+ "1003456 300 500 200 300 0 0 0 0 50 0\n"
+ "1001000 400 300 200 100 40 30 20 10 5 1\n";
+ std::unordered_map<uid_t, UidIoUsage> expectedSecondUsage =
+ {{1001234,
+ {.uid = 1001234,
+ .ios = {/*fgRdBytes=*/4000, /*bgRdBytes=*/0,
+ /*fgWrBytes=*/450, /*bgWrBytes=*/0, /*fgFsync=*/25,
+ /*bgFsync=*/0}}},
+ {1005678, {.uid = 1005678, .ios = {10, 900, 0, 400, 5, 10}}},
+ {1003456, {.uid = 1003456, .ios = {200, 0, 300, 0, 50, 0}}}};
ASSERT_TRUE(WriteStringToFile(secondSnapshot, tf.path));
ASSERT_RESULT_OK(uidIoStats.collect());
const auto& actualSecondUsage = uidIoStats.deltaStats();
- EXPECT_EQ(expectedSecondUsage.size(), actualSecondUsage.size());
-
- for (const auto& it : expectedSecondUsage) {
- if (actualSecondUsage.find(it.first) == actualSecondUsage.end()) {
- ADD_FAILURE() << "Expected uid " << it.first << " not found in the second snapshot";
- }
- const UidIoUsage& expected = it.second;
- const UidIoUsage& actual = actualSecondUsage.at(it.first);
- EXPECT_EQ(expected.uid, actual.uid);
- EXPECT_EQ(expected.ios, actual.ios)
- << "Unexpected I/O usage for uid " << it.first << " in second snapshot:.\nExpected:\n"
- << expected.ios.toString() << "\nActual:\n"<< actual.ios.toString();
- }
+ EXPECT_THAT(actualSecondUsage, UnorderedElementsAreArray(expectedSecondUsage))
+ << "Expected: " << toString(expectedSecondUsage)
+ << "Actual: " << toString(actualSecondUsage);
}
TEST(UidIoStatsTest, TestErrorOnInvalidStatFile) {
// Format: uid fgRdChar fgWrChar fgRdBytes fgWrBytes bgRdChar bgWrChar bgRdBytes bgWrBytes
// fgFsync bgFsync
- constexpr char contents[] =
- "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
- "1005678 500 100 30 50 300 400 100 200 45 60\n"
- "1009012 0 0 0 0 40000 50000 20000 30000 0 300\n"
- "1001000 4000 3000 2000 1000 CORRUPTED DATA\n";
+ constexpr char contents[] = "1001234 5000 1000 3000 500 0 0 0 0 20 0\n"
+ "1005678 500 100 30 50 300 400 100 200 45 60\n"
+ "1009012 0 0 0 0 40000 50000 20000 30000 0 300\n"
+ "1001000 4000 3000 2000 1000 CORRUPTED DATA\n";
TemporaryFile tf;
ASSERT_NE(tf.fd, -1);
ASSERT_TRUE(WriteStringToFile(contents, tf.path));
diff --git a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
index aae920a..f5dd7dc 100644
--- a/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogInternalHandlerTest.cpp
@@ -45,12 +45,14 @@
using aawi::ComponentType;
using aawi::ICarWatchdogServiceForSystem;
using aawi::ICarWatchdogServiceForSystemDefault;
-using aawi::IoOveruseConfiguration;
using aawi::PackageResourceOveruseAction;
+using aawi::ResourceOveruseConfiguration;
using ::android::sp;
+using ::android::String16;
using ::android::base::Result;
using ::android::binder::Status;
using ::testing::_;
+using ::testing::Pointer;
using ::testing::Return;
namespace {
@@ -66,7 +68,7 @@
-> Result<void> { return Result<void>{}; }) {}
~MockWatchdogBinderMediator() {}
- MOCK_METHOD(status_t, dump, (int fd, const Vector<String16>& args), (override));
+ MOCK_METHOD(status_t, dump, (int fd, const Vector<android::String16>& args), (override));
};
class ScopedChangeCallingUid : public RefBase {
@@ -369,22 +371,37 @@
ASSERT_FALSE(status.isOk()) << status;
}
-TEST_F(WatchdogInternalHandlerTest, TestUpdateIoOveruseConfiguration) {
+TEST_F(WatchdogInternalHandlerTest, TestUpdateResourceOveruseConfigurations) {
setSystemCallingUid();
- EXPECT_CALL(*mMockIoOveruseMonitor, updateIoOveruseConfiguration(ComponentType::SYSTEM, _))
+ EXPECT_CALL(*mMockIoOveruseMonitor, updateResourceOveruseConfigurations(_))
.WillOnce(Return(Result<void>()));
- Status status =
- mWatchdogInternalHandler->updateIoOveruseConfiguration(ComponentType::SYSTEM,
- IoOveruseConfiguration{});
+ Status status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
+ std::vector<ResourceOveruseConfiguration>{});
ASSERT_TRUE(status.isOk()) << status;
}
TEST_F(WatchdogInternalHandlerTest,
- TestErrorOnUpdateIoOveruseConfigurationWithNonSystemCallingUid) {
- EXPECT_CALL(*mMockIoOveruseMonitor, updateIoOveruseConfiguration(_, _)).Times(0);
- Status status =
- mWatchdogInternalHandler->updateIoOveruseConfiguration(ComponentType::SYSTEM,
- IoOveruseConfiguration{});
+ TestErrorOnUpdateResourceOveruseConfigurationsWithNonSystemCallingUid) {
+ EXPECT_CALL(*mMockIoOveruseMonitor, updateResourceOveruseConfigurations(_)).Times(0);
+ Status status = mWatchdogInternalHandler->updateResourceOveruseConfigurations(
+ std::vector<ResourceOveruseConfiguration>{});
+ ASSERT_FALSE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest, TestGetResourceOveruseConfigurations) {
+ setSystemCallingUid();
+ std::vector<ResourceOveruseConfiguration> configs;
+ EXPECT_CALL(*mMockIoOveruseMonitor, getResourceOveruseConfigurations(Pointer(&configs)))
+ .WillOnce(Return(Result<void>()));
+ Status status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
+ ASSERT_TRUE(status.isOk()) << status;
+}
+
+TEST_F(WatchdogInternalHandlerTest,
+ TestErrorOnGetResourceOveruseConfigurationsWithNonSystemCallingUid) {
+ EXPECT_CALL(*mMockIoOveruseMonitor, getResourceOveruseConfigurations(_)).Times(0);
+ std::vector<ResourceOveruseConfiguration> configs;
+ Status status = mWatchdogInternalHandler->getResourceOveruseConfigurations(&configs);
ASSERT_FALSE(status.isOk()) << status;
}
diff --git a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
index c7de12b..3873195 100644
--- a/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogPerfServiceTest.cpp
@@ -39,6 +39,7 @@
namespace automotive {
namespace watchdog {
+using ::android::String16;
using ::android::wp;
using ::android::automotive::watchdog::testing::LooperStub;
using ::android::base::Error;
diff --git a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
index 681d900..17edadf 100644
--- a/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
+++ b/cpp/watchdog/server/tests/WatchdogServiceHelperTest.cpp
@@ -22,7 +22,6 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/RefBase.h>
-#include <utils/String16.h>
namespace android {
namespace automotive {
@@ -41,7 +40,6 @@
using ::android::IBinder;
using ::android::RefBase;
using ::android::sp;
-using ::android::String16;
using ::android::base::Error;
using ::android::base::Result;
using ::android::binder::Status;
@@ -80,7 +78,7 @@
ComponentType componentType,
ApplicationCategoryType appCategoryType) {
PackageInfo packageInfo;
- packageInfo.packageIdentifier.name = String16(packageName);
+ packageInfo.packageIdentifier.name = packageName;
packageInfo.packageIdentifier.uid = uid;
packageInfo.uidType = uidType;
packageInfo.componentType = componentType;
@@ -329,7 +327,6 @@
TEST_F(WatchdogServiceHelperTest, TestGetPackageInfosForUids) {
std::vector<int32_t> uids = {1000};
std::vector<std::string> prefixesStr = {"vendor.package"};
- std::vector<String16> prefixesStr16 = {String16("vendor.package")};
std::vector<PackageInfo> expectedPackageInfo{
constructPackageInfo("vendor.package.A", 120000, UidType::NATIVE, ComponentType::VENDOR,
ApplicationCategoryType::OTHERS),
@@ -340,7 +337,7 @@
registerCarWatchdogService();
- EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getPackageInfosForUids(uids, prefixesStr16, _))
+ EXPECT_CALL(*mMockCarWatchdogServiceForSystem, getPackageInfosForUids(uids, prefixesStr, _))
.WillOnce(DoAll(SetArgPointee<2>(expectedPackageInfo), Return(Status::ok())));
Status status =
diff --git a/service/jni/Android.bp b/service/jni/Android.bp
index 6048d06..86f3455 100644
--- a/service/jni/Android.bp
+++ b/service/jni/Android.bp
@@ -14,6 +14,10 @@
//
//
//#################################
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_library_shared {
name: "libcarservicejni",
srcs: [
diff --git a/service/res/values-af/strings.xml b/service/res/values-af/strings.xml
index c4c74ee..819c007 100644
--- a/service/res/values-af/strings.xml
+++ b/service/res/values-af/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Luister na bestuurstaatveranderinge."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Gebruik motor se EVS-diens"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Teken in op EVS-videostrome"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitor motor se EVS-diensstatus"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor \'n status van CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Versoek die EVS-voorskouaktiwiteit"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Versoek die stelsel om die EVS-voorskouaktiwiteit te begin"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Beheer die EVS-voorskouaktiwiteit"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Beheer die EVS-voorskouaktiwiteit van die stelsel"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Gebruik die EVS-kamera"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Teken in op EVS-kamerastrome"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitor die status van die EVS-diens"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Luister na die statusveranderinge van die EVS-diens"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"toegang tot motor se gedetailleerde enjininligting"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Toegang tot jou motor se gedetailleerde enjininligting."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"toegang tot motor se brandstofdeur en laaipoort"</string>
diff --git a/service/res/values-am/strings.xml b/service/res/values-am/strings.xml
index 9de6091..9d327d9 100644
--- a/service/res/values-am/strings.xml
+++ b/service/res/values-am/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ለመኪና አነዳድ ሁኔታ ለውጦች ያዳምጡ።"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"የመኪና ኢቪኤስ አገልግሎት ይጠቀሙ"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"ለኢቪኤስ ቪዲዮ ዥረቶች ይመዝገቡ"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"የመኪና ኢቪኤስ አገልግሎት ሁኔታን ይከታተሉ"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"የCarEvsService ሁኔታን ይከታተሉ"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"የኢቪኤስ ቅድመ-እይታ እንቅስቃሴን መጠየቅ"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"የኢቪኤስ ቅድመ-እይታ እንቅስቃሴን ለማስጀመር ስርዓቱን መጠየቅ"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"የኢቪኤስ ቅድመ-እይታ እንቅስቃሴን መቆጣጠር"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"የስርዓቱን የኢቪኤስ ቅድመ-እይታ እንቅስቃሴ መቆጣጠር"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"የኢቪኤስ ካሜራን መጠቀም"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"ለኢቪኤስ የካሜራ ዥረቶች ደንበኝነት መመዝገብ"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"የኢቪኤስ አገልግሎት ሁኔታን መከታተል"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"የኢቪኤስ አገልግሎት ሁኔታ ለውጦችን ማዳመጥ"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"የመኪና ሞተርን ዝርዝሮች ድረስባቸው"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"የእርስዎን መኪና በዝርዝር የቀረበ የሞተር መረጃ ይድረሱበት።"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"የመኪናውን የነዳጅ በር እና የኃይል መሙያ በር ድረስበት"</string>
diff --git a/service/res/values-ar/strings.xml b/service/res/values-ar/strings.xml
index 7579241..ae10792 100644
--- a/service/res/values-ar/strings.xml
+++ b/service/res/values-ar/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"يمكنك الاستماع إلى التغيُّرات في حالة \"القيادة\"."</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_label_monitor_evs_status" msgid="8586151402220417700">"مراقبة حالة خدمة EVS للسيارة"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"مراقبة إحدى حالات CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"يمكنك الحصول على معلومات تفصيلية عن محرّك السيارة."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"الحصول على معلومات عن .باب خزان الوقود ومنفذ الشحن"</string>
diff --git a/service/res/values-as/strings.xml b/service/res/values-as/strings.xml
index d784eff..945a2b2 100644
--- a/service/res/values-as/strings.xml
+++ b/service/res/values-as/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"গাড়ী চালনাৰ স্থিতি সলনি হ’লে সেইয়া জানিব।"</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_label_monitor_evs_status" msgid="8586151402220417700">"গাড়ীৰ EVS ছাৰ্ভিচৰ স্থিতি নিৰীক্ষণ কৰক"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsServiceৰ এটা স্থিতি নিৰীক্ষণ কৰক"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"আপোনাৰ গাড়ীৰ ইঞ্জিনৰ সবিশেষ তথ্য এক্সেছ কৰিব।"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"গাড়ীৰ ইন্ধনৰ দৰ্জা আৰু চাৰ্জ প’ৰ্ট এক্সেছ কৰিব"</string>
diff --git a/service/res/values-az/strings.xml b/service/res/values-az/strings.xml
index 453e877..62aa062 100644
--- a/service/res/values-az/strings.xml
+++ b/service/res/values-az/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Sürücülük vəziyyəti dəyişikliklərini dinləmək."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Avtomobilin EVS Xidmətindən istifadə edin"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS video yayımlarına abunə olun"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Avtomobilin EVS Xidmət statusunu izləyin"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Avtomobilin EVS Xidmət statusunu izləyin"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS önizləmə fəaliyyətini istəmək"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Sistemdən EVS önizləmə fəaliyyətini başlatmasını istəmək"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS önizləmə fəaliyyətinə nəzarət etmək"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Sistemin EVS önizləmə fəaliyyətinə nəzarət etmək"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS kamerasını istifadə etmək"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS kamera yayımlarına abunə olmaq"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS xidmətinin vəziyyətini izləmək"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS xidmətinin vəziyyət dəyişikliklərini dinləmək"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"avtomobilin mühərrik məlumatlarına giriş"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Avtomobilin ətraflı mühərrik məlumatlarına giriş."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"avtomobilin yanacaq bölməsinin qapağı və enerji doldurma portuna giriş"</string>
diff --git a/service/res/values-b+sr+Latn/strings.xml b/service/res/values-b+sr+Latn/strings.xml
index 90278ce..1e47f09 100644
--- a/service/res/values-b+sr+Latn/strings.xml
+++ b/service/res/values-b+sr+Latn/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Slušanje promene statusa vožnje."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Korišćenje usluge EVS za automobil"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Praćenje video strimove EVS-a"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Praćenje statusa usluge EVS za automobil"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Praćenje statusa koji se odnosi na CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Zahtev za EVS aktivnosti prikaza"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Zahtev da sistem pokrene EVS aktivnosti prikaza"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kontrola EVS aktivnosti prikaza"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontrola EVS aktivnosti prikaza za sistem"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Korišćenje EVS kamere"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Korišćenje EVS strimova kamera"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Praćenje statusa EVS usluge"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Praćenje promena statusa usluge EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"pristup detaljnim podacima o motoru automobila"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pristup detaljnim podacima o motoru automobila."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristup poklopcu rezervoara za gorivo i portu za punjenje"</string>
diff --git a/service/res/values-be/strings.xml b/service/res/values-be/strings.xml
index 0629c33..d08e25e 100644
--- a/service/res/values-be/strings.xml
+++ b/service/res/values-be/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Адсочванне змен падчас язды."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Выкарыстоўваць Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Падпісацца на відэастрымы EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Ажыццяўляць маніторынг стану Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Ажыццяўляць маніторынг стану CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ да падрабязнай інфармацыі пра рухавік аўтамабіля."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"дазволіць доступ да лючка паліўнага бака і порта зарадкі аўтамабіля"</string>
diff --git a/service/res/values-bg/strings.xml b/service/res/values-bg/strings.xml
index 5073a45..869a7d9 100644
--- a/service/res/values-bg/strings.xml
+++ b/service/res/values-bg/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Слушане за промени в състоянието на шофиране."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Използване на автомобилната услуга за ЕПС"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Абониране за видеопотоците на ЕПС"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Наблюдаване на състоянието на автомобилната услуга за ЕПС"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Наблюдаване на състоянието на CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Заявяване на активността за визуализация на ЕПС"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Поискване от системата да стартира активността за визуализация на ЕПС"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Управление на активността за визуализация на ЕПС"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Управление на активността за визуализация на ЕПС в системата"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Използване на камерата на ЕПС"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Абониране за потоците на камерата на ЕПС"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Наблюдение на състоянието на услугата за ЕПС"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Слушане на промените в състоянието на услугата за ЕПС"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"достъп до подробни данни за двигателя на автомобила"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Достъп до подробна информация за двигателя на автомобила."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"достъп до капака за резервоара и порта за зареждане на автомобила"</string>
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index bc1f480..753cc2b 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ড্রাইভিংয়ের স্ট্যাটাস পরিবর্তন করার বিষয়ে শোনা।"</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_label_monitor_evs_status" msgid="8586151402220417700">"গাড়ি EVS পরিষেবার স্ট্যাটাস মনিটর করুন"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService-এর স্ট্যাটাস মনিটর করুন"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"আপনার গাড়ির ইঞ্জিনের বিশদ তথ্য অ্যাক্সেস করা।"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"গাড়ির জ্বালানীর চেম্বারের ঢাকনা ও চার্জ পোর্ট অ্যাক্সেস করা"</string>
diff --git a/service/res/values-bs/strings.xml b/service/res/values-bs/strings.xml
index 9dc82a7..1fd16cc 100644
--- a/service/res/values-bs/strings.xml
+++ b/service/res/values-bs/strings.xml
@@ -21,17 +21,17 @@
<string name="car_permission_label_camera" msgid="3725702064841827180">"pristupiti kameri automobila"</string>
<string name="car_permission_desc_camera" msgid="917024932164501426">"Pristupiti kameri(ama) automobila."</string>
<string name="car_permission_label_energy" msgid="7409144323527821558">"pristupiti informacijama o energiji automobila"</string>
- <string name="car_permission_desc_energy" msgid="3392963810053235407">"Pristupiti informacijama o energiji automobila."</string>
- <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"podesi preostali domet automobila"</string>
- <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"Podesi vrijednost preostalog dometa automobila."</string>
+ <string name="car_permission_desc_energy" msgid="3392963810053235407">"pristupiti informacijama o energiji automobila"</string>
+ <string name="car_permission_label_adjust_range_remaining" msgid="839033553999920138">"podesiti preostali domet automobila"</string>
+ <string name="car_permission_desc_adjust_range_remaining" msgid="2369321650437370673">"podesiti vrijednost preostalog dometa automobila"</string>
<string name="car_permission_label_hvac" msgid="1499454192558727843">"pristupiti grijanju, ventilaciji i klimatizaciji automobila"</string>
<string name="car_permission_desc_hvac" msgid="3754229695589774195">"Pristupiti grijanju, ventilaciji i klimatizaciji automobila."</string>
<string name="car_permission_label_mileage" msgid="4661317074631150551">"pristupiti informacijama o pređenim kilometrima automobila"</string>
- <string name="car_permission_desc_mileage" msgid="7179735693278681090">"Pristupiti informacijama o pređenim kilometrima."</string>
+ <string name="car_permission_desc_mileage" msgid="7179735693278681090">"pristupiti informacijama o pređenim kilometrima"</string>
<string name="car_permission_label_speed" msgid="1149027717860529745">"očitati brzinu automobila"</string>
- <string name="car_permission_desc_speed" msgid="2047965198165448241">"Pristupiti informacijama o brzini automobila."</string>
+ <string name="car_permission_desc_speed" msgid="2047965198165448241">"pristupiti informacijama o brzini automobila"</string>
<string name="car_permission_label_vehicle_dynamics_state" msgid="313779267420048367">"pristupiti stanju dinamike automobila"</string>
- <string name="car_permission_desc_vehicle_dynamics_state" msgid="8891506193446375660">"Pristupiti stanju dinamike automobila."</string>
+ <string name="car_permission_desc_vehicle_dynamics_state" msgid="8891506193446375660">"pristupiti stanju dinamike automobila"</string>
<string name="car_permission_label_vendor_extension" msgid="7141601811734127361">"pristupiti kanalu trgovca automobilima"</string>
<string name="car_permission_desc_vendor_extension" msgid="2970718502334714035">"Pristupiti kanalu trgovca automobilima radi razmjene posebnih informacija o automobilu."</string>
<string name="car_permission_label_radio" msgid="6009465291685935112">"upravljati radiom automobila"</string>
@@ -47,11 +47,11 @@
<string name="car_permission_label_mock_vehicle_hal" msgid="7198852512207405935">"emulirati HAL vozila"</string>
<string name="car_permission_label_receive_ducking" msgid="4884538660766756573">"prijem događaja sa smanjivanjem jačine zvuka tokom govora"</string>
<string name="car_permission_desc_receive_ducking" msgid="776376388266656512">"Dozvoljava aplikaciji da primi obavještenje kada se glasnoća smanji uslijed reproduciranja drugog zvučnog zapisa u automobilu."</string>
- <string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"Emulirati HAL vozila u svrhu internog testiranja."</string>
- <string name="car_permission_desc_audio_volume" msgid="536626185654307889">"Kontrolirati jačinu zvuka u automobilu."</string>
+ <string name="car_permission_desc_mock_vehicle_hal" msgid="5235596491098649155">"emulirati HAL vozila u svrhu internog testiranja"</string>
+ <string name="car_permission_desc_audio_volume" msgid="536626185654307889">"kontrolirati jačinu zvuka u automobilu"</string>
<string name="car_permission_desc_audio_settings" msgid="7192007170677915937">"Kontrolirajte postavke zvuka automobila."</string>
<string name="car_permission_label_control_app_blocking" msgid="9112678596919993386">"Blokiranje aplikacija"</string>
- <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"Kontrolirati blokiranje aplikacija tokom vožnje."</string>
+ <string name="car_permission_desc_control_app_blocking" msgid="7539378161760696190">"kontrolirati blokiranje aplikacija tokom vožnje"</string>
<string name="car_permission_car_navigation_manager" msgid="5895461364007854077">"Upravitelj navigacije"</string>
<string name="car_permission_desc_car_navigation_manager" msgid="6188751054665471537">"Dostaviti podatke o navigaciji kontrolnoj tabli"</string>
<string name="car_permission_car_display_in_cluster" msgid="4005987646292458684">"Direktno iscrtavanje na kontrolnoj ploči"</string>
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Slušati izmjene stanja vožnje."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Korištenje usluge Car EVS"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Pretplaćivanje na video prijenose usluge EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Nadziranje statusa usluge Car EVS"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Nadziranje statusa usluge CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Zahtijevanje pregleda aktivnosti usluge EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Zahtijevanje od sistema da pokrene aktivnost pregleda usluge EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kontroliranje aktivnosti pregleda usluge EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontroliranje pregleda aktivnosti sistema usluge EVS"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Korištenje kamere usluge EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Pretplata na prijenose kamere usluge EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Praćenje statusa usluge EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Slušanje promjena statusa usluge EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"pristupiti detaljima o motoru automobila"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pristupiti detaljnim informacijama o motoru automobila."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristupiti poklopcu rezervoara za gorivo i priključku za punjenje"</string>
diff --git a/service/res/values-ca/strings.xml b/service/res/values-ca/strings.xml
index 81a5c20..6250c91 100644
--- a/service/res/values-ca/strings.xml
+++ b/service/res/values-ca/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Escolta els canvis en l\'estat de conducció."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utilitza el servei EVS del cotxe"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscriu-me a les reproduccions en continu de vídeo d\'EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitora l\'estat del servei EVS del cotxe"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitora un estat de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Sol·licitar l\'activitat de previsualització d\'EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Sol·licitar al sistema que iniciï l\'activitat de previsualització d\'EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar l\'activitat de previsualització d\'EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar l\'activitat de previsualització d\'EVS del sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utilitzar la càmera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscriure\'s a les reproduccions en continu de la càmera EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorar l\'estat del servei d\'EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Escoltar els canvis d\'estat del servei EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"accedeix a la informació detallada sobre el motor del cotxe"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accedeix a la informació detallada sobre el motor del cotxe."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"accedeix a la porta del combustible i al port de càrrega del cotxe"</string>
diff --git a/service/res/values-cs/strings.xml b/service/res/values-cs/strings.xml
index 0e06abf..a717cba 100644
--- a/service/res/values-cs/strings.xml
+++ b/service/res/values-cs/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Poslech změn stavu jízdy autem."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Používání služby EVS pro auto"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Odběr videostreamů EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Sledování stavu služby EVS pro auto"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Sledování stavu CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Žádost o náhled aktivity EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Žádost systému o spuštění aktivity náhledu EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Ovládání aktivity náhledu EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Ovládání aktivity náhledu systému EVS"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Používání kamery EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Odběr streamů z kamery EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Sledování stavu služby EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Poslech změn stavu služby EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"přístup k podrobným informacím o motoru auta"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Přístup k podrobným údajům o motoru auta."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"přístup ke vstupu do nádrže a nabíjecímu portu auta"</string>
diff --git a/service/res/values-da/strings.xml b/service/res/values-da/strings.xml
index 506603e..a9393f0 100644
--- a/service/res/values-da/strings.xml
+++ b/service/res/values-da/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Lyt til ændringer i tilstanden Kører."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Brug Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonner på EVS-videostreams"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Følg med i status for Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Følg med i en status for CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Anmode om aktivitet med EVS-forhåndsvisning"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Anmode systemet om at åbne aktivitet med EVS-forhåndsvisning"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Styre aktivitet med EVS-forhåndsvisning"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontrollere systemets aktivitet med EVS-forhåndsvisning"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Bruge EVS-kameraet"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonnere på EVS-kamerastreams"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Holde øje med EVS-tjenestens status"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Høre statusændringer for EVS-tjenesten"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"få adgang til detaljerede oplysninger om bilens motor"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Få adgang til detaljerede oplysninger om bilens motor."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få adgang til bilens tankdæksel og opladningsport"</string>
diff --git a/service/res/values-de/strings.xml b/service/res/values-de/strings.xml
index 5a97e2f..f936a9d 100644
--- a/service/res/values-de/strings.xml
+++ b/service/res/values-de/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Informationen zu Fahrzustandsänderungen entgegennehmen."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Car EVS Service verwenden"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS-Videostreams abonnieren"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Car EVS Service-Status überwachen"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Einen Status von CarEvsService überwachen"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS-Vorschauaktivität anfordern"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Das System auffordern, die EVS-Vorschauaktivität zu starten"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS-Vorschauaktivität steuern"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"EVS-Vorschauaktivität des Systems steuern"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS-Kamera verwenden"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS-Kamerastreams abonnieren"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Status des EVS-Diensts prüfen"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Statusänderungen des EVS-Diensts prüfen"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"auf detaillierte Motorinformationen zuzugreifen"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Auf detaillierte Motorinformationen zugreifen."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"auf die Tankklappe und die Ladebuchse zuzugreifen"</string>
diff --git a/service/res/values-el/strings.xml b/service/res/values-el/strings.xml
index edec482..540e78a 100644
--- a/service/res/values-el/strings.xml
+++ b/service/res/values-el/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ακρόαση αλλαγών κατάστασης οδήγησης."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Χρήση Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Εγγραφή στις ροές βίντεο EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Παρακολούθηση κατάστασης Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Παρακολούθηση κατάστασης CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Πρόσβαση σε λεπτομερείς πληροφορίες του κινητήρα του αυτοκινήτου."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"πρόσβαση στο πορτάκι του ρεζερβουάρ και της θύρας φόρτισης"</string>
diff --git a/service/res/values-en-rAU/strings.xml b/service/res/values-en-rAU/strings.xml
index 30854bd..06574a9 100644
--- a/service/res/values-en-rAU/strings.xml
+++ b/service/res/values-en-rAU/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</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_monitor_evs_status" msgid="8586151402220417700">"Monitor car EVS service status"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor a status of CarEvsService"</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 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>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Listen to the status changes of the EVS service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"access car’s engine detailed"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
diff --git a/service/res/values-en-rCA/strings.xml b/service/res/values-en-rCA/strings.xml
index 30854bd..06574a9 100644
--- a/service/res/values-en-rCA/strings.xml
+++ b/service/res/values-en-rCA/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</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_monitor_evs_status" msgid="8586151402220417700">"Monitor car EVS service status"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor a status of CarEvsService"</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 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>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Listen to the status changes of the EVS service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"access car’s engine detailed"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
diff --git a/service/res/values-en-rGB/strings.xml b/service/res/values-en-rGB/strings.xml
index 30854bd..06574a9 100644
--- a/service/res/values-en-rGB/strings.xml
+++ b/service/res/values-en-rGB/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</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_monitor_evs_status" msgid="8586151402220417700">"Monitor car EVS service status"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor a status of CarEvsService"</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 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>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Listen to the status changes of the EVS service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"access car’s engine detailed"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
diff --git a/service/res/values-en-rIN/strings.xml b/service/res/values-en-rIN/strings.xml
index 30854bd..06574a9 100644
--- a/service/res/values-en-rIN/strings.xml
+++ b/service/res/values-en-rIN/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to driving state changes."</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_monitor_evs_status" msgid="8586151402220417700">"Monitor car EVS service status"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor a status of CarEvsService"</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 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>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Listen to the status changes of the EVS service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"access car’s engine detailed"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
diff --git a/service/res/values-en-rXC/strings.xml b/service/res/values-en-rXC/strings.xml
index 0a638d9..b0dfaa1 100644
--- a/service/res/values-en-rXC/strings.xml
+++ b/service/res/values-en-rXC/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Listen to Driving state changes."</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_monitor_evs_status" msgid="8586151402220417700">"Monitor Car EVS Service status"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitor a status of CarEvsService"</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_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>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Listen to the status changes of the EVS service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"access car’s engine detailed"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Access your car’s detailed engine information."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"access car’s fuel door and charge port"</string>
diff --git a/service/res/values-es-rUS/strings.xml b/service/res/values-es-rUS/strings.xml
index f7b3971..f1c077b 100644
--- a/service/res/values-es-rUS/strings.xml
+++ b/service/res/values-es-rUS/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Escuchar los cambios de estado de conducción."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Usar servicio EVS del vehículo"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Suscribirse a las transmisiones de video por Internet de EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Supervisar el estado del servicio EVS del vehículo"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Supervisar un estado de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitar la actividad de vista previa de EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitar que el sistema inicie la actividad de vista previa de EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar la actividad de vista previa de EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar la actividad de vista previa de EVS del sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Usar la cámara de EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Suscribirse a transmisiones de cámaras de EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Supervisar el estado del servicio de EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Detectar los cambios de estado del servicio de EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"acceder a detalles del motor del vehículo"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada del motor del vehículo."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder a la puerta de combustible del vehículo y al puerto de carga"</string>
diff --git a/service/res/values-es/strings.xml b/service/res/values-es/strings.xml
index 79e7605..bdbe760 100644
--- a/service/res/values-es/strings.xml
+++ b/service/res/values-es/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Detectar cambios en el estado de conducción."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utilizar servicio EVS del coche"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Suscribirse a streams de vídeo de EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitorizar estado del servicio EVS del coche"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitorizar un estado de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitar la actividad de vista previa de EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitar al sistema que inicie la actividad de vista previa de EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar la actividad de vista previa de EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar la actividad de vista previa de EVS del sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utilizar la cámara de EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Suscribirse a flujos de cámara de EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizar el estado del servicio EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Monitorizar los cambios de estado del servicio EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"acceder a los detalles del motor del coche"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada sobre el motor del coche."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder al puerto de carga y al depósito de combustible"</string>
diff --git a/service/res/values-et/strings.xml b/service/res/values-et/strings.xml
index 67e48e5..ea80e70 100644
--- a/service/res/values-et/strings.xml
+++ b/service/res/values-et/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Sõitmise oleku muudatuste kuulamine."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Auto EVS-i teenuse kasutamine"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS-i videovoogude kasutajaks registreerumine"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Auto EVS-i teenuse oleku jälgimine"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Teenuse CarEvsService oleku jälgimine"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS-i eelvaatetegevuste taotlemine"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Süsteemil EVS-i eelvaatetegevuste käivitamise taotlemine"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS-i eelvaatetegevuste juhtimine"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Süsteemi EVS-i eelvaatetegevuste kontrollimine"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS-i kaamera kasutamine"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS-i kaameravoogude tellimine"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS-i teenuse oleku jälgimine"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS-i teenuse olekumuudatuste kuulmine"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"juurdepääs auto mootori üksikasjalikule teabele"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Juurdepääs auto üksikasjalikule mootoriteabele."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"juurdepääs auto kütusepaagi luugile ja avale"</string>
diff --git a/service/res/values-eu/strings.xml b/service/res/values-eu/strings.xml
index a12a1d5..addec81 100644
--- a/service/res/values-eu/strings.xml
+++ b/service/res/values-eu/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Entzun gidatze-egoeraren inguruko aldaketak."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Erabili autoko EVS zerbitzua"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Harpidetu EVSren bideo-igorpenetara"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Kontrolatu autoko EVS zerbitzuaren egoera"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Kontrolatu CarEvsService-ren egoera"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Eskatu EVSko aurrebistaren jarduera"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Eskatu sistemari EVSko aurrebista abiarazteko"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kontrolatu EVSko aurrebistaren jarduera"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontrolatu sistemaren EVSko aurrebistaren jarduera"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Erabili EVSaren kamera"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Harpidetu EVSaren kamera-igorpenetara"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Gainbegiratu EVS zerbitzuaren egoera"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Gainbegiratu EVS zerbitzuaren egoera-aldaketak"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"atzitu autoaren motorrari buruzko informazio xehatua"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Atzitu autoaren motorrari buruzko informazio xehatua."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"atzitu autoaren erregai-deposituaren ataka eta korrontera konektatzeko ataka"</string>
diff --git a/service/res/values-fa/strings.xml b/service/res/values-fa/strings.xml
index 3a827c4..6700349 100644
--- a/service/res/values-fa/strings.xml
+++ b/service/res/values-fa/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"به تغییرات حالت رانندگی گوش دهید."</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_label_monitor_evs_status" msgid="8586151402220417700">"نظارت بر وضعیت «سرویس EVS خودرو»"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"نظارت بر وضعیت CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"به اطلاعات کامل موتور خودرو دسترسی پیدا کنید."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"دسترسی به درب باک و درگاه شارژ خودرو"</string>
diff --git a/service/res/values-fi/strings.xml b/service/res/values-fi/strings.xml
index 281dadb..44e5096 100644
--- a/service/res/values-fi/strings.xml
+++ b/service/res/values-fi/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"kuunnella ajotilan muutoksia"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"käyttää auton EVS-palvelua"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"tilata EVS-videostriimit"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"seurata auton EVS-palvelun tilaa"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"valvoa CarEvsServicen tilaa"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"pyytää EVS-esikatselutoimintaa"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"pyytää järjestelmää käynnistämään EVS-esikatselutoiminnan"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"ohjata EVS-esikatselutoimintaa"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"ohjata järjestelmän EVS-esikatselutoimintaa"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"käyttää EVS-kameraa"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"tilata EVS-kamerastriimit"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"seurata EVS-palvelun tilaa"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"kuunnella muutoksia EVS-palvelun tilassa"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"käyttää auton moottorin yksityiskohtaisia tietoja"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"käyttää auton moottorin yksityiskohtaisia tietoja"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"käyttää auton polttoaineluukkua ja latausliitäntää"</string>
diff --git a/service/res/values-fr-rCA/strings.xml b/service/res/values-fr-rCA/strings.xml
index fb79451..5878a5d 100644
--- a/service/res/values-fr-rCA/strings.xml
+++ b/service/res/values-fr-rCA/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Détecter les changements relatifs à la conduite."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utiliser le service EVS du véhicule"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"S\'abonner aux flux vidéo EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Surveiller l\'état du service EVS du véhicule"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Surveiller l\'état de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Demander l\'activité d\'aperçu EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Demander au système de lancer l\'activité d\'aperçu EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Contrôler l\'activité d\'aperçu EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Contrôler l\'activité d\'aperçu EVS du système"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utiliser la caméra EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"S\'abonner aux flux de la caméra EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Surveiller l\'état du service EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Écouter les changements d\'état du service EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"accéder aux détails sur le moteur de la voiture"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accéder aux renseignements détaillés sur le moteur de votre voiture."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"accéder à la porte du réservoir de carburant et au port de recharge de la voiture"</string>
diff --git a/service/res/values-fr/strings.xml b/service/res/values-fr/strings.xml
index 32def69..407ab8a 100644
--- a/service/res/values-fr/strings.xml
+++ b/service/res/values-fr/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Détecter les changements de conduite."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utiliser Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"S\'abonner aux flux vidéo EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Surveiller un état Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Surveiller un état CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Demander l\'activité d\'aperçu EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Demander le lancement de l\'activité d\'aperçu EVS par le système"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Contrôler l\'activité d\'aperçu EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Contrôler l\'activité d\'aperçu EVS du système"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utiliser la caméra EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"S\'abonner aux flux de la caméra EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Surveiller l\'état du service EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Écouter les changements d\'état du service EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"Accéder aux informations détaillées sur le moteur de la voiture"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Accéder à des informations détaillées sur le moteur de la voiture."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accéder à la trappe à carburant et au port de recharge de la voiture"</string>
diff --git a/service/res/values-gl/strings.xml b/service/res/values-gl/strings.xml
index 22e8d56..24fcbb1 100644
--- a/service/res/values-gl/strings.xml
+++ b/service/res/values-gl/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Escoitar cambios no estado de condución."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utilizar o servizo EVS do coche"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscribirse ás transmisións en vídeo de EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Supervisar o estado do servizo EVS do coche"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Supervisar un estado de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitar a actividade de vista previa do servizo EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitar que o sistema inicie a actividade de vista previa do servizo EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar a actividade de vista previa do servizo EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar a actividade de vista previa do servizo EVS do sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Usar a cámara do servizo EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscribirse á reprodución en tempo real das cámaras do servizo EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Supervisar o estado do servizo EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Supervisar os cambios de estado do servizo EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"acceder a información do motor do coche"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acceder a información detallada do motor do coche."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acceder ao depósito de combustible e ao porto de carga do coche"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 9a690a0..931b0e7 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -96,8 +96,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ડ્રાઇવ કરવાની સ્થિતિના ફેરફારો વિશે સાંભળો."</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_label_monitor_evs_status" msgid="8586151402220417700">"કાર EVS સર્વિસના સ્ટેટસનું નિરીક્ષણ કરો"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"કાર 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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"તમારી કારના એન્જિનની વિગતવાર માહિતીને ઍક્સેસ કરો."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"કારના ઇંધણના દરવાજા અને ચાર્જ પોર્ટને ઍક્સેસ કરો"</string>
diff --git a/service/res/values-hi/strings.xml b/service/res/values-hi/strings.xml
index 789c78b..6ff2cbd 100644
--- a/service/res/values-hi/strings.xml
+++ b/service/res/values-hi/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"गाड़ी चलाते समय होने वाले बदलावों को सुन सकता है."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"कार की ईवीएस सेवा का इस्तेमाल करें"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"ईवीएस वीडियो स्ट्रीम की सदस्यता लें"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"कार की ईवीएस सेवा की स्थिति को मॉनिटर करें"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService की स्थिति को मॉनिटर करें"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"ईवीएस की झलक से जुड़ी गतिविधि का अनुरोध करें"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"ईवीएस की झलक से जुड़ी गतिविधि लॉन्च करने के लिए सिस्टम से अनुरोध करें"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"ईवीएस की झलक से जुड़ी गतिविधि कंट्रोल करें"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"सिस्टम की ईवीएस की झलक से जुड़ी गतिविधि कंट्रोल करें"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"ईवीएस कैमरा इस्तेमाल करें"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"ईवीएस कैमरा स्ट्रीम की सदस्यता लें"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"ईवीएस सेवा के स्टेटस पर नज़र रखें"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"ईवीएस सेवा के स्टेटस में हुए बदलावों पर नज़र रखें"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"कार के इंजन की जानकारी ऐक्सेस कर सकता है"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"आपकी कार के इंजन की पूरी जानकारी ऐक्सेस कर सकता है."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कार की ईंधन टंकी का ढक्कन और चार्जिंग पोर्ट ऐक्सेस कर सकता है"</string>
diff --git a/service/res/values-hr/strings.xml b/service/res/values-hr/strings.xml
index 57358ca..0662614 100644
--- a/service/res/values-hr/strings.xml
+++ b/service/res/values-hr/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"slušati promjene stanja vožnje"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"koristiti EVS uslugu za automobil"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"pretplatiti se na videostreamove EVS-a"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"nadzirati status EVS usluge za automobil"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"nadzirati status koji se odnosi na CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"zahtijevati aktivnost pregleda EVS-a"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"zahtijevati da sustav pokrene aktivnost pregleda EVS-a"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"upravljati aktivnošću pregleda EVS-a"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"upravljati aktivnošću pregleda EVS-a u sustavu"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"koristiti kameru EVS-a"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"pretplatiti se na streamove kamere EVS-a"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"nadzirati status usluge EVS-a"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"slušati promjene statusa usluge EVS-a"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"pristupiti pojedinostima o automobilskom motoru"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"pristupiti detaljnim podacima o motoru automobila"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pristupiti poklopcu spremnika za gorivo i priključku za punjenje na automobilu"</string>
diff --git a/service/res/values-hu/strings.xml b/service/res/values-hu/strings.xml
index 7772d51..07e69cd 100644
--- a/service/res/values-hu/strings.xml
+++ b/service/res/values-hu/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Meghallgathatja a vezetési állapot változásait."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Az autó EVS-szolgáltatásának használata"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Feliratkozás az EVS-videóstreamekre"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Az autó EVS-szolgáltatása állapotának figyelése"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService állapotának figyelése"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Az EVS-előnézeti tevékenység kérése"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Annak kérése a rendszertől, hogy indítsa el az EVS-előnézeti tevékenységet"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Az EVS-előnézeti tevékenységek irányítása"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"A rendszer EVS-előnézeti tevékenységeinek irányítása"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Az EVS-kamera használata"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Feliratkozás EVS-kamerastreamekre"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Az EVS szolgáltatás állapotának figyelése"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Az EVS szolgáltatás állapotváltozásainak figyelése"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"hozzáférhet az autó motorjával kapcsolatos részletes adatokhoz"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Hozzáférhet az autó motorjának részletes adataihoz."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"hozzáférhet az autó tanksapkájához és töltőnyílásához"</string>
diff --git a/service/res/values-hy/strings.xml b/service/res/values-hy/strings.xml
index 859e64a..d48f548 100644
--- a/service/res/values-hy/strings.xml
+++ b/service/res/values-hy/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Հետագծել վարելու ռեժիմի փոփոխությունները։"</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_label_monitor_evs_status" msgid="8586151402220417700">"Վերահսկել ավտոմեքենայի EVS ծառայության կարգավիճակը"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Վերահսկել CarEvsService-ի կարգավիճակը"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Օգտագործել շարժիչի մանրամասն տվյալները։"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"օգտագործել մեքենայի վառելիքի բաքի կափարիչի և լիցքավորման վարդակի տվյալները"</string>
diff --git a/service/res/values-in/strings.xml b/service/res/values-in/strings.xml
index 9f8ad12..3a039b6 100644
--- a/service/res/values-in/strings.xml
+++ b/service/res/values-in/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Memproses perubahan status Mengemudi."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Menggunakan CarEvsService"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Berlangganan streaming video EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Memantau status CarEvsService"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Memantau status CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Meminta aktivitas pratinjau EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Meminta sistem meluncurkan aktivitas pratinjau EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Mengontrol aktivitas pratinjau EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Mengontrol aktivitas pratinjau EVS dari sistem"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Menggunakan kamera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Berlangganan streaming kamera EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Memantau status layanan EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Mendengarkan perubahan status layanan EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"mengakses detail mesin mobil"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Mengakses informasi mendetail tentang mesin mobil Anda."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"mengakses tutup tangki bahan bakar dan lubang colokan pengisi daya mobil"</string>
diff --git a/service/res/values-is/strings.xml b/service/res/values-is/strings.xml
index 855d694..45932c6 100644
--- a/service/res/values-is/strings.xml
+++ b/service/res/values-is/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Hlusta á breytingar í akstursstöðu."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Nota EVS-þjónustu bíls"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Gerast áskrifandi að EVS-vídeóstraumi"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Fylgjast með stöðu EVS-þjónustu bíls"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Fylgjast með stöðu CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Biðja um EVS-forskoðunaraðgerðir"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Biðja kerfið um að ræsa EVS-forskoðunaraðgerðir"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Stjórna EVS-forskoðunaraðgerðum"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Stjórna EVS-forskoðunaraðgerðum í kerfinu"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Nota EVS-myndavélina"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Fá áskrift að EVS-myndavélastreymi"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Fylgjast með stöðu EVS-þjónustunnar"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Hlusta eftir stöðubreytingum EVS-þjónustunnar"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"fá aðgang að upplýsingum um vél"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Fá aðgang að ítarlegum upplýsingum um vél bílsins."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"fá aðgang að bensínloki og hleðslutengi bílsins"</string>
diff --git a/service/res/values-it/strings.xml b/service/res/values-it/strings.xml
index a6a299b..cc45ee2 100644
--- a/service/res/values-it/strings.xml
+++ b/service/res/values-it/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Consente di ascoltare le modifiche dello stato Alla guida."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Usa il servizio CarEvsService"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Consente di abbonarsi ai video stream EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitora lo stato del servizio CarEvsService"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Consente di monitorare lo stato del servizio CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Richiedere l\'attività di anteprima EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Richiedere al sistema di lanciare l\'attività di anteprima EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controllare l\'attività di anteprima EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controllare l\'attività di anteprima EVS del sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utilizzare la videocamera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abbonarsi agli stream della videocamera EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorare lo stato del servizio EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Ascoltare le modifiche dello stato del servizio EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"Accesso alle informazioni dettagliate sul motore dell\'automobile"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Consente di accedere a informazioni dettagliate sul motore dell\'automobile."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"Accesso al coperchio del serbatoio e allo sportello di ricarica dell\'automobile"</string>
diff --git a/service/res/values-iw/strings.xml b/service/res/values-iw/strings.xml
index 466fe82..af01ba3 100644
--- a/service/res/values-iw/strings.xml
+++ b/service/res/values-iw/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"האזנה לשינויים במצב הנהיגה."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"שימוש ב-Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"הרשמה לשידורי וידאו של EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"מעקב אחר הסטטוס של Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"מעקב אחר הסטטוס של CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"גישה למידע מפורט על מנוע הרכב."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"גישה לפתח מכל הדלק וליציאת הטעינה של הרכב"</string>
diff --git a/service/res/values-ja/strings.xml b/service/res/values-ja/strings.xml
index 21b1504..83f15a3 100644
--- a/service/res/values-ja/strings.xml
+++ b/service/res/values-ja/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"運転状態の変更にアクセスします。"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Car EVS Service の使用"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS 動画ストリーミングのチャンネル登録"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Car EVS Service のステータスのモニタリング"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService のステータスのモニタリング"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"車の詳細なエンジン情報にアクセスします。"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"車の給油口と充電ポートへのアクセス"</string>
diff --git a/service/res/values-ka/strings.xml b/service/res/values-ka/strings.xml
index d460e84..90100ea 100644
--- a/service/res/values-ka/strings.xml
+++ b/service/res/values-ka/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"მანქანის მართვის მდგომარეობის ცვლილებებისთვის თვალის მიდევნება."</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_label_monitor_evs_status" msgid="8586151402220417700">"მანქანის EVS სერვისის სტატუსის მონიტორინგი"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService სტატუსის მონიტორინგი"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"მანქანის ძრავის დეტალურ ინფორმაციაზე წვდომა."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"მანქანის საწვავის ავზის ხუფზე და დამტენ პორტზე წვდომა"</string>
diff --git a/service/res/values-kk/strings.xml b/service/res/values-kk/strings.xml
index edfa2c8..af0f662 100644
--- a/service/res/values-kk/strings.xml
+++ b/service/res/values-kk/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Көлік жүргізу күйінің өзгерістерін білу."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Car EVS Service пайдалану"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS бейне ағыны қызметіне жазылу"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Car EVS Service күйін қадағалау"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService күйін қадағалау"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Көліктің қозғалтқышы туралы толық ақпаратты пайдалану."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"көліктің жанармай құю саңылауын және зарядтау портын пайдалану"</string>
diff --git a/service/res/values-km/strings.xml b/service/res/values-km/strings.xml
index 34da856..26c0862 100644
--- a/service/res/values-km/strings.xml
+++ b/service/res/values-km/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ស្តាប់អំពីការផ្លាស់ប្ដូរស្ថានភាពបើកបរ។"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"ប្រើ Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"ជាវការស្ទ្រីមវីដេអូ EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"ត្រួតពិនិត្យស្ថានភាព Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"ត្រួតពិនិត្យស្ថានភាព CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ចូលប្រើព័ត៌មានលម្អិតអំពីម៉ាស៊ីនរថយន្តរបស់អ្នក។"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ចូលប្រើគម្របសាំង និងរន្ធសាកអាគុយរថយន្ត។"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index beffe7f..9ee5d88 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ಚಾಲನೆಯ ಸ್ಥಿತಿಯ ಬದಲಾವಣೆಗಳನ್ನು ಆಲಿಸಿ."</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_label_monitor_evs_status" msgid="8586151402220417700">"ಕಾರ್ EVS ಸೇವೆಯ ಸ್ಥಿತಿಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService ನ ಸ್ಥಿತಿಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ಕಾರಿನ ಇಂಜಿನ್ನ ವಿವರಣೆಯ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ಕಾರಿನ ಇಂಧನ ಪಂಪ್ನ ಮುಚ್ಚಳ ಮತ್ತು ಚಾರ್ಜ್ ಪೋರ್ಟ್ ಮಾಹಿತಿ ಪಡೆಯಿರಿ"</string>
diff --git a/service/res/values-ko/strings.xml b/service/res/values-ko/strings.xml
index d8a5609..53bf0c9 100644
--- a/service/res/values-ko/strings.xml
+++ b/service/res/values-ko/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"운전 상태 변화를 감지합니다."</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_label_monitor_evs_status" msgid="8586151402220417700">"자동차 EVS 서비스 상태 모니터링하기"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"자동차 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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"차량의 상세한 엔진 정보에 액세스합니다."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"차량 주유구 캡 및 충전 포트 액세스"</string>
diff --git a/service/res/values-ky/strings.xml b/service/res/values-ky/strings.xml
index c8a7a04..5954cb6 100644
--- a/service/res/values-ky/strings.xml
+++ b/service/res/values-ky/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Унаа айдоо абалынын өзгөрүүлөрүн угуу."</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_label_monitor_evs_status" msgid="8586151402220417700">"Унаанын EVS кызматынын статусуна көз салуу"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService статусуна көз салуу"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Унааңыздын кыймылдаткычы тууралуу толук маалыматты көрүү."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"унаанын май куюучу тешигине жана кубаттоо оюкчасына мүмкүнчүлүк алуу"</string>
diff --git a/service/res/values-lo/strings.xml b/service/res/values-lo/strings.xml
index 6f6ae23..5522c9d 100644
--- a/service/res/values-lo/strings.xml
+++ b/service/res/values-lo/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ຟັງການປ່ຽນແປງສະພາບການຂັບຂີ່."</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_label_monitor_evs_status" msgid="8586151402220417700">"ຕິດຕາມສະຖານະການບໍລິການ EVS ຂອງລົດ"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"ຕິດຕາມສະຖານະຂອງ CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ເຂົ້າເຖິງຂໍ້ມູນເຄື່ອງຈັກລະອຽດຂອງລົດທ່ານ."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ເຂົ້າເຖິງຂໍ້ມູນຝານໍ້າມັນ ແລະ ຮູສາກໄຟຂອງລົດ"</string>
diff --git a/service/res/values-lt/strings.xml b/service/res/values-lt/strings.xml
index 56162d1..db60428 100644
--- a/service/res/values-lt/strings.xml
+++ b/service/res/values-lt/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Klausyti vairavimo būsenos pakeitimų."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Naudoti automobilio EVS paslaugą"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Prenumeruoti EVS vaizdo transliacijas"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Stebėti automobilio EVS paslaugos būseną"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Stebėti automobilio EVS paslaugos būseną"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Pateikti užklausą dėl EVS peržiūros veiklos"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Pateikti sistemai užklausą paleisti EVS peržiūros veiklą"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Valdyti EVS peržiūros veiklą"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Valdyti sistemos EVS peržiūros veiklą"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Naudoti EVS kamerą"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Prenumeruoti EVS kameros transliacijas"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Stebėti EVS paslaugos būseną"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Klausyti EVS paslaugos būsenos pakeitimus"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"pasiekti išsamią automobilio variklio informaciją"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Pasiekti išsamią automobilio variklio informaciją."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"pasiekti automobilio degalų bako dureles ir įkrovimo prievadą"</string>
diff --git a/service/res/values-lv/strings.xml b/service/res/values-lv/strings.xml
index ff63984..ece37da 100644
--- a/service/res/values-lv/strings.xml
+++ b/service/res/values-lv/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Uztvert kustības stāvokļa izmaiņas."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Izmantot automašīnas EVS pakalpojumu"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonēt EVS video plūsmas"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Pārraudzīt automašīnas EVS pakalpojuma statusu"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Pārraudzīt CarEvsService statusu"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Pieprasīt EVS darbību priekšskatījumu"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Pieprasīt sistēmai palaist EVS darbību priekšskatījumu"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kontrolēt EVS darbību priekšskatījumu"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontrolēt sistēmas EVS darbību priekšskatījumu"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Izmantot EVS kameru"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonēt EVS kameras straumes"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Pārraudzīt EVS pakalpojuma darbību"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Pārraudzīt EVS pakalpojuma statusa izmaiņas"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"piekļūt detalizētai informācijai par automašīnas dzinēju"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Piekļūt detalizētai informācijai par automašīnas dzinēju."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"piekļūt automašīnas degvielas tvertnes vāciņam un uzlādes pieslēgvietai"</string>
diff --git a/service/res/values-mk/strings.xml b/service/res/values-mk/strings.xml
index a246914..bcb9ba6 100644
--- a/service/res/values-mk/strings.xml
+++ b/service/res/values-mk/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ги слуша промените во состојбата на возење."</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_label_monitor_evs_status" msgid="8586151402220417700">"Следење статус на „EVS-сервис за автомобили“"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Следење статус на CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"да ја побара активноста за преглед на електричните возила"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"да побара системот да ја стартува активноста за преглед на електричните возила"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"да ја контролира активноста за преглед на електричните возила"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"да ја контролира активноста за преглед на системот на електричните возила"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"да ја користи камерата на електричните возила"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"да се претплати на преносите од камерите на електричните возила"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"да го следи статусот на услугата за електричните возила"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"да ги слуша промените во статусот на услугата за електричните возила"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"пристапува до деталите за моторот на автомобилот"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Пристапува до деталните информации за моторот на автомобилот."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"пристапува до вратата за гориво и портата за полнење на автомобилот"</string>
diff --git a/service/res/values-ml/strings.xml b/service/res/values-ml/strings.xml
index 489e38e..6958ab1 100644
--- a/service/res/values-ml/strings.xml
+++ b/service/res/values-ml/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ഡ്രൈവിംഗ് നിലയിലെ മാറ്റങ്ങൾ ശ്രദ്ധിക്കുക."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Car EVS Service ഉപയോഗിക്കുക"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS വീഡിയോ സ്ട്രീമുകളുടെ വരിക്കാരാകുക"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Car EVS Service സ്റ്റാറ്റസ് നിരീക്ഷിക്കുക"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService-ന്റെ ഒരു സ്റ്റാറ്റസ് നിരീക്ഷിക്കുക"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"നിങ്ങളുടെ കാറിൻ്റെ വിശദമായ എഞ്ചിൻ വിവരങ്ങൾ ആക്സസ് ചെയ്യുക."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"കാറിൻ്റെ ഇന്ധന വാതിലും ചാർജ് പോർട്ടും ആക്സസ് ചെയ്യുക"</string>
diff --git a/service/res/values-mn/strings.xml b/service/res/values-mn/strings.xml
index adffa3f..077e6f1 100644
--- a/service/res/values-mn/strings.xml
+++ b/service/res/values-mn/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Жолоодлогын төлөвийн өөрчлөлтийг сонсох."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Car EVS Service-г ашиглах"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS видео дамжуулалтыг захиалах"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Car EVS Service-н төлөвийг хянах"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService-н төлөвийг хянах"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Таны машины хөдөлгүүрийн дэлгэрэнгүй мэдээлэлд хандах."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"машины шатахууны савны таг болон цэнэглэх оролтод хандах"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index 598e9d5..ecf0111 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ड्रायव्हिंगच्या स्थितीतील बदल ऐका."</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_label_monitor_evs_status" msgid="8586151402220417700">"कार EVS सेवेच्या स्थितीचे परीक्षण करा"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService च्या स्थितीचे परीक्षण करा"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"तुमच्या कारच्या इंजिनची तपशीलवार माहिती अॅक्सेस करा."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कारचा इंधन भरण्याचा दरवाजा आणि चार्ज पोर्ट अॅक्सेस करा"</string>
diff --git a/service/res/values-ms/strings.xml b/service/res/values-ms/strings.xml
index 644c1a4..dc6cdf3 100644
--- a/service/res/values-ms/strings.xml
+++ b/service/res/values-ms/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Dengar Perubahan keadaan pemanduan."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Gunakan Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Langgan strim video EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Pantau status Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Pantau status CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Minta aktiviti pratonton EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Minta sistem untuk melancarkan aktiviti pratonton EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kawal aktiviti pratonton EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kawal aktiviti pratonton EVS bagi sistem"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Gunakan kamera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Langgan strim kamera EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Pantau status perkhidmatan EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Dengar perubahan status perkhidmatan EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"akses perincian enjin kereta anda"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Akses maklumat terperinci enjin kereta anda."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"akses penutup tangki bahan api dan port pengecasan kereta"</string>
diff --git a/service/res/values-my/strings.xml b/service/res/values-my/strings.xml
index 4dac308..38711d4 100644
--- a/service/res/values-my/strings.xml
+++ b/service/res/values-my/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"\'ယာဉ်မောင်းနှင်မှုဆိုင်ရာ\' အခြေအနေ ပြောင်းလဲမှုများကို စောင့်ကြည့်ပါမည်။"</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_label_monitor_evs_status" msgid="8586151402220417700">"‘ကား EVS ဝန်ဆောင်မှု’ အခြေအနေကို စောင့်ကြည့်ရန်"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService အခြေအနေကို စောင့်ကြည့်ရန်"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"သင့်ကား၏ အသေးစိတ် အင်ဂျင်အချက်အလက်ကို ရယူပါမည်။"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ကား၏ ဆီတိုင်ကီတံခါးပေါက်နှင့် အားသွင်းသည့်အပေါက်ကို အသုံးပြုပါမည်"</string>
diff --git a/service/res/values-nb/strings.xml b/service/res/values-nb/strings.xml
index e2863a3..8815c68 100644
--- a/service/res/values-nb/strings.xml
+++ b/service/res/values-nb/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Lytt etter endringer i kjøretilstanden."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Bruk Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonner på EVS-videodatastrømmer"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Overvåk status for Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Overvåk en status i CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"be om EVS-forhåndsvisningsaktiviteten"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"be systemet om å starte EVS-forhåndsvisningsaktiviteten"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"kontrollere EVS-forhåndsvisningsaktiviteten"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"kontrollere systemets EVS-forhåndsvisningsaktivitet"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"bruke EVS-kameraet"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"abonnere på EVS-kamerastrømmer"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"holde øye med EVS-tjenestens status"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"lytte til EVS-tjenestens statusendringer"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"få informasjon om bilmotoren"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Tilgang til detaljert informasjon om bilmotoren."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"få tilgang til tanklokket og ladeporten på bilen"</string>
diff --git a/service/res/values-ne/strings.xml b/service/res/values-ne/strings.xml
index c3ef77d..adb1532 100644
--- a/service/res/values-ne/strings.xml
+++ b/service/res/values-ne/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ड्राइभिङको स्थितिमा हुने परिवर्तनहरू सुन्ने।"</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_label_monitor_evs_status" msgid="8586151402220417700">"कार EVS सेवाको स्थिति निगरानी गर्नुहोस्"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService को स्थिति निगरानी गर्नुहोस्"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"तपाईंको कारको इन्जिनको विस्तृत जानकारीमाथि पहुँच राख्ने।"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"कारको इन्धन हाल्ने ट्याङ्कीको बिर्को तथा चार्ज गर्ने पोर्टमाथि पहुँच राख्ने"</string>
diff --git a/service/res/values-nl/strings.xml b/service/res/values-nl/strings.xml
index 2c98420..c2e2f5c 100644
--- a/service/res/values-nl/strings.xml
+++ b/service/res/values-nl/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Luisteren naar wijzigingen van rijstand."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"EVS-autoservice gebruiken"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Abonneren op EVS-videostreams"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Status van EVS-autoservice monitoren"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"De status van een EVS-autoservice monitoren"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"De EVS-voorbeeldactiviteit aanvragen"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Het systeem vragen de EVS-voorbeeldactiviteit te starten"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"De EVS-voorbeeldactiviteit beheren"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"De EVS-voorbeeldactiviteit van het systeem beheren"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"De EVS-camera gebruiken"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Abonneren op EVS-camerastreams"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"De status van de EVS-service monitoren"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Luisteren naar de statuswijzigingen van de EVS-service"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"toegang tot gedetailleerde informatie over motor van auto"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Toegang tot gedetailleerde informatie over motor van auto."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"toegang tot tankklep en oplaadpoort van auto"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index 94bc53d..4574131 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ଡ୍ରାଇଭିଂ ଷ୍ଟେଟ୍ରେ ହେଉଥିବା ପରିବର୍ତ୍ତନକୁ ଶୁଣନ୍ତୁ।"</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_label_monitor_evs_status" msgid="8586151402220417700">"କାର EVS ସେବାର ସ୍ଥିତିକୁ ନିରୀକ୍ଷଣ କରନ୍ତୁ"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsServiceର ଏକ ସ୍ଥିତିକୁ ନିରୀକ୍ଷଣ କରନ୍ତୁ"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ଆପଣଙ୍କ କାର୍\'ର ବିସ୍ତୃତ ଇଞ୍ଜିନ୍ ସୂଚନାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"କାର୍\'ର ଫୁଏଲ୍ ଡୋର୍ ଏବଂ ଚାର୍ଜ ପୋର୍ଟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
diff --git a/service/res/values-pa/strings.xml b/service/res/values-pa/strings.xml
index c269132..1442080 100644
--- a/service/res/values-pa/strings.xml
+++ b/service/res/values-pa/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ਗੱਡੀ ਚਲਾਉਣ ਦੀ ਸਥਿਤੀ ਵਿੱਚ ਹੋਣ ਵਾਲੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਜਾਣਨਾ।"</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_label_monitor_evs_status" msgid="8586151402220417700">"ਕਾਰ ਦੀ EVS ਸੇਵਾ ਸਥਿਤੀ ਦਾ ਨਿਰੀਖਣ ਕਰੋ"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService ਦੀ ਸਥਿਤੀ ਦਾ ਨਿਰੀਖਣ ਕਰੋ"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ਤੁਹਾਡੀ ਕਾਰ ਦੇ ਇੰਜਣ ਦੀ ਵੇਰਵੇ ਸਹਿਤ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ।"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"ਕਾਰ ਦੀ ਈਂਧਣ ਵਾਲੀ ਜਗ੍ਹਾ ਅਤੇ ਚਾਰਜ ਪੋਰਟ ਤੱਕ ਪਹੁੰਚ"</string>
diff --git a/service/res/values-pl/strings.xml b/service/res/values-pl/strings.xml
index 8112978..75a4393 100644
--- a/service/res/values-pl/strings.xml
+++ b/service/res/values-pl/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Nasłuchiwanie zmian podczas jazdy samochodem."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Używaj usługi EVS w samochodzie"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subskrybuj strumienie wideo z EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitoruj stan usługi EVS w samochodzie"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitoruj stan usługi CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Wysyłaj prośbę o podgląd EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Wysyłaj do systemu żądanie uruchomienia podglądu EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Steruj podglądem EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Steruj podglądem EVS w systemie"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Używaj kamery EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subskrybuj strumienie z kamer EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitoruj stan usługi EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Wykrywaj zmiany stanu usługi EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"dostęp do szczegółowych informacji na temat silnika"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Dostęp do szczegółowych informacji o silniku."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"dostęp do drzwiczek wlewu paliwa i portu ładowania samochodu"</string>
diff --git a/service/res/values-pt-rPT/strings.xml b/service/res/values-pt-rPT/strings.xml
index be9687a..b7371e6 100644
--- a/service/res/values-pt-rPT/strings.xml
+++ b/service/res/values-pt-rPT/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ouvir as alterações ao estado de condução."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Utilizar o Serviço de EVS do carro"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Subscrever streams de vídeo de EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitorizar o estado do Serviço de EVS do carro"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitorizar um estado do CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitar a atividade de pré-visualização de EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitar ao sistema o lançamento da atividade de pré-visualização de EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar a atividade de pré-visualização de EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar a atividade de pré-visualização de EVS do sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Utilizar a câmara de EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Subscrever as streams da câmara de EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorizar o estado do serviço de EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Ouvir as alterações de estado do serviço de EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"aceder ao motor detalhado do automóvel"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Aceder às informações detalhadas do motor do automóvel."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"aceder à porta de carregamento e à tampa do depósito de combustível do automóvel"</string>
diff --git a/service/res/values-pt/strings.xml b/service/res/values-pt/strings.xml
index adb559b..75fa00c 100644
--- a/service/res/values-pt/strings.xml
+++ b/service/res/values-pt/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ouvir quando o estado de condução for alterado."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Usar Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Assinar streams de vídeo do sistema de visualização estendida (EVS, na sigla em inglês)"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Monitorar o status de Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitorar o status de CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Solicitar a atividade de visualização de EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Solicitar que o sistema inicie a atividade de visualização de EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Controlar a atividade de visualização de EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Controlar a atividade de visualização de EVS do sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Usar a câmera EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Assinar streams da câmera EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorar o status do serviço EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Detectar mudanças de status do serviço EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"acessar detalhes do motor do carro"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Acessar informações detalhadas do motor do carro."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"acessar as entradas de combustível e carregamento do carro"</string>
diff --git a/service/res/values-ro/strings.xml b/service/res/values-ro/strings.xml
index 756cbc1..15ae8ae 100644
--- a/service/res/values-ro/strings.xml
+++ b/service/res/values-ro/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Ascultă modificările stării La volan."</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_monitor_evs_status" msgid="8586151402220417700">"Monitorizați starea de serviciu EVS a mașinii"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Monitorizați o stare pentru CarEvsService"</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>
diff --git a/service/res/values-ru/strings.xml b/service/res/values-ru/strings.xml
index d9d33ab..12bc582 100644
--- a/service/res/values-ru/strings.xml
+++ b/service/res/values-ru/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Отслеживание изменений режима \"За рулем\"."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Использовать Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Подписаться на видеотрансляции EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Отслеживать статус Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Отслеживать статус CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ к подробным данным о двигателе."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"доступ к лючку топливного бака и порту зарядки"</string>
diff --git a/service/res/values-si/strings.xml b/service/res/values-si/strings.xml
index 3124d63..8fa7e68 100644
--- a/service/res/values-si/strings.xml
+++ b/service/res/values-si/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"රිය පැදවීම් තත්ත්ව වෙනස්කම්වලට සවන් දෙන්න."</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_label_monitor_evs_status" msgid="8586151402220417700">"මෝටර් රථ EVS සේවා තත්ත්වය නිරීක්ෂණය කරන්න"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService හි තත්ත්වය නිරීක්ෂණය කරන්න"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"ඔබේ මෝටර් රථයේ විස්තරාත්මක එන්ජින් තොරතුරුවලට ප්රවේශ වන්න."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"මෝටර් රථයේ ඉන්ධන දොර සහ ආරෝපණ කවුළුවට ප්රවේශ වන්න"</string>
diff --git a/service/res/values-sk/strings.xml b/service/res/values-sk/strings.xml
index 1dff40c..50cfa76 100644
--- a/service/res/values-sk/strings.xml
+++ b/service/res/values-sk/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Počúvanie zmien stavu jazdy."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Používanie služby Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Prihlásenie na odber videostreamov EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Sledovanie stavu v službe Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Sledovanie stavu v službe CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Odosielanie žiadostí o aktivitu ukážky EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Odosielanie žiadostí systému o spustenie aktivity ukážky EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Ovládanie aktivity ukážky EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Ovládanie aktivity ukážky EVS systému"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Používanie kamery EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Prihlásenie sa na odber prenosov kamery EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Monitorovanie stavu služby EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Príjem zmien stavu služby EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"získať prístup k podrobnostiam o motore auta"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Získajte prístup k podrobným informáciám o motore auta."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"získať prístup k dvierkam palivovej nádrže a nabíjaciemu portu"</string>
diff --git a/service/res/values-sl/strings.xml b/service/res/values-sl/strings.xml
index 96ea63d..611c7e9 100644
--- a/service/res/values-sl/strings.xml
+++ b/service/res/values-sl/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Poslušanje sprememb voznih stanj."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Uporaba storitve EVS v avtomobilu"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Naročanje na videotoke storitve EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Spremljanje storitve EVS v avtomobilu"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Spremljanje stanja storitve CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Zahtevanje dejavnosti predogleda storitve EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Zahtevanje zagona dejavnosti predogleda storitve EVS od sistema"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Nadziranje dejavnosti predogleda storitve EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Nadziranje dejavnosti predogleda storitve EVS sistema"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Uporaba kamere storitve EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Naročanje na toke kamere storitve EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Nadziranje stanja storitve EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Poslušanje sprememb stanja storitve EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"dostop do podrobnih podatkov o motorju avtomobila"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Dostop do podrobnih podatkov o motorju avtomobila."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"dostop do pokrova rezervoarja in polnilnih vrat avtomobila"</string>
diff --git a/service/res/values-sq/strings.xml b/service/res/values-sq/strings.xml
index cbba61c..6099665 100644
--- a/service/res/values-sq/strings.xml
+++ b/service/res/values-sq/strings.xml
@@ -97,8 +97,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Dëgjo ndryshimet e gjendjes së lëvizjes me makinë."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Të përdorin shërbimin EVS të makinës"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Të abonohen në transmetimet me video të sistemit EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Të monitorojnë statusin e shërbimit EVS të makinës"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Të monitorojnë një status të CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Të kërkojnë aktivitetin e pamjes paraprake nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Të kërkojnë që sistemi të hapë aktivitetin e pamjes paraprake nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Të kontrollojnë aktivitetin e pamjes paraprake nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Të kontrollojnë aktivitetin e pamjes paraprake të sistemit nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Të përdorin kamerën nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Të abonohen te transmetimet e kamerave nëpërmjet shërbimit EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Të monitorojnë statusin e shërbimit EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Të dëgjojnë ndryshimet e statusit të shërbimit EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"qasu te informacionet e detajuara të motorit të makinës"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Qasje në informacionet e detajuara të motorit të makinës."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"qasu te porta e karburantit të makinës dhe te porta e karikimit"</string>
diff --git a/service/res/values-sr/strings.xml b/service/res/values-sr/strings.xml
index d93e8d6..cab0182 100644
--- a/service/res/values-sr/strings.xml
+++ b/service/res/values-sr/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Слушање промене статуса вожње."</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_label_monitor_evs_status" msgid="8586151402220417700">"Праћење статуса услуге EVS за аутомобил"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Праћење статуса који се односи на CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Приступ детаљним подацима о мотору аутомобила."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"приступ поклопцу резервоара за гориво и порту за пуњење"</string>
diff --git a/service/res/values-sv/strings.xml b/service/res/values-sv/strings.xml
index c9aac4b..ef1bbc5 100644
--- a/service/res/values-sv/strings.xml
+++ b/service/res/values-sv/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Reagera på ändringar av bilkörningsläget."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Använd Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Prenumerera på EVS-videoströmmar"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Bevaka status för Car EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Bevaka status för CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Begära EVS-förhandsgranskningsaktivitet"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Begära att systemet ska starta EVS-förhandsgranskningsaktivitet"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Styra EVS-förhandsgranskningsaktivitet"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Styra systemets EVS-förhandsgranskningsaktivitet"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Använda EVS-kameran"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Prenumerera på EVS-kameraströmmar"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Bevaka EVS-tjänstens status"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Bevaka statusförändringar för EVS-tjänsten"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"åtkomst till detaljerad motorinformation för bilen"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Åtkomst till detaljerad information om bilens motor."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"åtkomst till bilens tanklucka och laddningsport"</string>
diff --git a/service/res/values-sw/strings.xml b/service/res/values-sw/strings.xml
index 71793bb..e56616e 100644
--- a/service/res/values-sw/strings.xml
+++ b/service/res/values-sw/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Kusikiliza mabadiliko katika hali ya Kuendesha gari."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Tumia Huduma ya EVS ya Gari"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Jisajili kwa video za kutiririsha za EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Fuatilia hali ya Huduma ya EVS ya Gari"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Fuatilia hali ya CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Kuomba shughuli za kukagua EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Kuomba mfumo uanzishe shughuli za kukagua EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kudhibiti shughuli za kukagua EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kudhibiti shughuli za kukagua EVS kwenye mfumo"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Kutumia kamera ya EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Kujisajili kwenye mitiririko ya kamera ya EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Kufuatilia hali ya huduma ya EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Kufuatilia mabadiliko ya hali ya huduma ya EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"kufikia maelezo ya usafi wa injini ya gari"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Kufikia maelezo ya kina ya injini ya gari lako."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"kufikia kifuniko cha sehemu ya kuwekea mafuta ya gari na mlango wa kuchaji"</string>
diff --git a/service/res/values-ta/strings.xml b/service/res/values-ta/strings.xml
index 042e268..931ffd9 100644
--- a/service/res/values-ta/strings.xml
+++ b/service/res/values-ta/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"காரை இயக்கும் நிலையில் ஏற்படும் மாற்றங்களை அறிய வேண்டும்."</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_label_monitor_evs_status" msgid="8586151402220417700">"காரின் EVS சேவை நிலையைக் கண்காணிக்கும்"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"காரின் 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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"காரின் இன்ஜின் குறித்த முழுமையான தகவலை அணுக வேண்டும்."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"காரின் எரிபொருள் மூடியையும் சார்ஜ் போர்ட்டையும் அணுக வேண்டும்"</string>
diff --git a/service/res/values-te/strings.xml b/service/res/values-te/strings.xml
index 3e82f57..7099686 100644
--- a/service/res/values-te/strings.xml
+++ b/service/res/values-te/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"డ్రైవింగ్ స్థితి మార్పులను వినగలవు."</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_label_monitor_evs_status" msgid="8586151402220417700">"కార్ EVS సర్వీస్ స్టేటస్ను పర్యవేక్షించండి"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService స్టేటస్ను పర్యవేక్షించండి"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"మీ కారు యొక్క సమగ్ర ఇంజిన్ సమాచారాన్ని యాక్సెస్ చేయగలవు."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"కారు ఇంధన డోర్ మరియు ఛార్జ్ పోర్ట్ను యాక్సెస్ చేయగలవు"</string>
diff --git a/service/res/values-th/strings.xml b/service/res/values-th/strings.xml
index d7552ed..8bd6876 100644
--- a/service/res/values-th/strings.xml
+++ b/service/res/values-th/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"ฟังการเปลี่ยนแปลงสถานะการขับรถ"</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_label_monitor_evs_status" msgid="8586151402220417700">"ตรวจสอบสถานะบริการ EVS ในรถยนต์"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"ตรวจสอบสถานะของ CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"เข้าถึงข้อมูลเครื่องยนต์ของรถโดยละเอียด"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"เข้าถึงฝาถังน้ำมันและพอร์ตชาร์จ"</string>
diff --git a/service/res/values-tl/strings.xml b/service/res/values-tl/strings.xml
index d4c21d7..7e1a9dc 100644
--- a/service/res/values-tl/strings.xml
+++ b/service/res/values-tl/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Makinig sa mga Mga pagbabago ng status ng pagmamaneho."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Gamitin ang Serbisyo sa EVS na Kotse"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Mag-subscribe sa mga video stream ng EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Subaybayan ang status ng Serbisyo sa EVS na Kotse"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Magsubaybay ng status ng CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Hilingin ang aktibidad ng pag-preview ng EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Hilingin sa system na ilunsad ang aktibidad ng pag-preview ng EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kontrolin ang aktibidad ng pag-preview ng EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kontrolin ang aktibidad ng pag-preview ng EVS ng system"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Gamitin ang camera ng EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Mag-subscribe sa mga stream ng camera ng EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Subaybayan ang status ng serbisyo ng EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Pakinggan ang mga pagbabago sa status ng serbisyo ng EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"i-access ang mga detalye ng makina ng sasakyan"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"I-access ang detalyadong impormasyon sa makina ng iyong sasakyan."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"i-access ang takip ng gasolina at charge port ng sasakyan"</string>
diff --git a/service/res/values-tr/strings.xml b/service/res/values-tr/strings.xml
index 65af936..d741315 100644
--- a/service/res/values-tr/strings.xml
+++ b/service/res/values-tr/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Araç kullanma durumundaki değişiklikleri dinleme."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Araç EVS Hizmetini kullan"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS video akışına abone ol"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Araç EVS Hizmet durumunu izle"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService durumunu izle"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS önizleme etkinliği talep etme"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Sistemden EVS önizleme etkinliği başlatmasını isteme"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS önizleme etkinliğini kontrol etme"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Sistemin Genişletilmiş Görüş Sistemi (EVS) önizleme etkinliğini kontrol etme"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS kamerasını kullanma"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS kamera yayınlarını kullanabilme"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS hizmetinin durumunu izleme"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS hizmetinin durum değişikliklerini izleme"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"aracın motoruyla ilgili ayrıntılara erişim"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Aracınızın ayrıntılı motor bilgilerine erişim."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"aracın yakıt kapağına ve şarj bağlantı noktasına erişim"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 7a089a8..bbed5e8 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Відстеження змін стану кермування."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Використовувати сервіс Car EVS"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Підписуватися на відеопотоки сервісу EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Стежити за статусом сервісу Car EVS"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Стежити за статусом сервісу CarEvsService"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Доступ до детальної інформації про двигун автомобіля."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"доступ до даних про кришку паливного бака чи порт заряджання автомобіля"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index a3e89c2..3c2ac8e 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"کار چلانے کے دوران کی تبدیلیوں کے بارے میں سنیں۔"</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_label_monitor_evs_status" msgid="8586151402220417700">"کار کی EVS سروس کے اسٹیٹس کو مانیٹر کریں"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService کے اسٹیٹس کی نگرانی کریں"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"اپنی کار کے انجن کی تفصیلی معلومات تک رسائی حاصل کریں۔"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"کار کے ایندھن کے دروازے اور چارج پورٹ تک رسائی حاصل کریں"</string>
diff --git a/service/res/values-uz/strings.xml b/service/res/values-uz/strings.xml
index 25a7e8c..92d3528 100644
--- a/service/res/values-uz/strings.xml
+++ b/service/res/values-uz/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Avtomobilda rejimining oʻzgarishini kuzatish."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Avtomobil EVS xizmatidan foydalanish"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"EVS video strimingiga obuna boʻlish"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Avtomoil EVS xizmati holatini nazorat qilish"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"CarEvsService holatini nazorat qilish"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"EVS nazar solish harakati talabini yuborish"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Tizimda EVS nazar solish harakatini ishga tushirish talabini yuborish"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"EVS nazar solish harakatlarini boshqarish"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Tizimning EVS nazar solish harakatlarini boshqarish"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"EVS kamerasidan foydalanish"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"EVS kamera strimlariga obuna boʻlish"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"EVS xizmati holatini nazorat qilish"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"EVS xizmati holatidagi oʻzgarishlarni kuzatish"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"avtomobil motori haqidagi batafsil axborotga kirish"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Avtomobilning motori haqidagi batafsil axborotga kirish."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"avtomobilning yonilgʻi darajasi va quvvatlash porti haqidagi axborotga kirish"</string>
diff --git a/service/res/values-vi/strings.xml b/service/res/values-vi/strings.xml
index 83ea162..0851457 100644
--- a/service/res/values-vi/strings.xml
+++ b/service/res/values-vi/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Nghe những thay đổi về trạng thái Lái xe."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Sử dụng dịch vụ CarEvsService"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Theo dõi luồng video của EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Theo dõi trạng thái CarEvsService"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Theo dõi trạng thái CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Yêu cầu hoạt động xem trước qua EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Yêu cầu hệ thống triển khai hoạt động xem trước qua EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Kiểm soát hoạt động xem trước qua EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Kiểm soát hoạt động xem trước của hệ thống qua EVS"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Sử dụng camera qua EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Đăng ký xem video của camera phát trực tuyến qua EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Theo dõi sự thay đổi trạng thái của dịch vụ EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Theo dõi sự thay đổi trạng thái của dịch vụ EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"truy cập vào thông tin chi tiết về động cơ ô tô"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Truy cập vào thông tin chi tiết về động cơ trên ô tô của bạn."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"truy cập vào cổng sạc và cổng nhiên liệu của ô tô"</string>
diff --git a/service/res/values-zh-rCN/strings.xml b/service/res/values-zh-rCN/strings.xml
index ff5a377..d79368b 100644
--- a/service/res/values-zh-rCN/strings.xml
+++ b/service/res/values-zh-rCN/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"监听驾车状态变化。"</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_label_monitor_evs_status" msgid="8586151402220417700">"监控汽车 EVS 服务状态"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"监控 CarEvsService 的状态"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"访问汽车的详细引擎信息。"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"访问汽车的油箱盖和充电端口信息"</string>
diff --git a/service/res/values-zh-rHK/strings.xml b/service/res/values-zh-rHK/strings.xml
index 201defa..70727f7 100644
--- a/service/res/values-zh-rHK/strings.xml
+++ b/service/res/values-zh-rHK/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"聽取駕駛狀態變動。"</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"使用 Car EVS Service"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"訂閱電動車影片串流"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"監控 Car EVS Service 狀態"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"監控 CarEvsService 狀態"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"存取汽車引擎詳情。"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"存取汽車油箱蓋及充電埠"</string>
diff --git a/service/res/values-zh-rTW/strings.xml b/service/res/values-zh-rTW/strings.xml
index 8952ecd..af77102 100644
--- a/service/res/values-zh-rTW/strings.xml
+++ b/service/res/values-zh-rTW/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"監聽駕駛狀態變更。"</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_label_monitor_evs_status" msgid="8586151402220417700">"監控車輛 EVS 服務狀態"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"監控 CarEvsService 狀態"</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_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>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"存取車輛的詳細引擎資訊。"</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"存取車輛的油孔蓋和充電口"</string>
diff --git a/service/res/values-zu/strings.xml b/service/res/values-zu/strings.xml
index a2716ad..7d79009 100644
--- a/service/res/values-zu/strings.xml
+++ b/service/res/values-zu/strings.xml
@@ -95,8 +95,14 @@
<string name="car_permission_desc_driving_state" msgid="2684025262811635737">"Lale izinguquko zesimo sokushayela."</string>
<string name="car_permission_label_use_evs_service" msgid="1729276125209310607">"Sebenzisa Isevisi Yemoto ye-EVS"</string>
<string name="car_permission_desc_use_evs_service" msgid="2374737642186632816">"Bhalisa ekudlalweni kwevidiyo kwe-EVS"</string>
- <string name="car_permission_label_monitor_evs_status" msgid="8586151402220417700">"Qapha isimo Sesevisi Yemoto ye-EVS Service"</string>
- <string name="car_permission_desc_monitor_evs_status" msgid="9211849809250999081">"Qapha isimo se-CarEvsService"</string>
+ <string name="car_permission_label_request_evs_activity" msgid="3906551972883482883">"Cela umsebenzi wokubuka kuqala kwe-EVS"</string>
+ <string name="car_permission_desc_request_evs_activity" msgid="4582768053649138488">"Cela isistimu iqalise umsebenzi wokubuka kuqala kwe-EVS"</string>
+ <string name="car_permission_label_control_evs_activity" msgid="2030069860204405679">"Lawula umsebenzi wokubuka kuqala kwe-EVS"</string>
+ <string name="car_permission_desc_control_evs_activity" msgid="691646545916976346">"Lawula ukubuka kuqala komsebenzi we-EVS yesistimu"</string>
+ <string name="car_permission_label_use_evs_camera" msgid="3607720208623955067">"Sebenzisa ikhamera ye-EVS"</string>
+ <string name="car_permission_desc_use_evs_camera" msgid="1625845902221003985">"Bhalisa ekusakazeni kwekhamera ye-EVS"</string>
+ <string name="car_permission_label_monitor_evs_status" msgid="2091521314159379622">"Qapha isimo sesevisi ye-EVS"</string>
+ <string name="car_permission_desc_monitor_evs_status" msgid="2764278897143573535">"Lalela isimo sezinguquko zesevisi ye-EVS"</string>
<string name="car_permission_label_car_engine_detailed" msgid="8911992719173587337">"finyelela injini yemoto enemininingwane"</string>
<string name="car_permission_desc_car_engine_detailed" msgid="1746863362811347700">"Finyelela ulwazi lwenjini olunemininingwane lwemoto yakho."</string>
<string name="car_permission_label_car_energy_ports" msgid="8548990315169219454">"iinyelela umnyango kaphethiloli nembobo yokushaja"</string>
diff --git a/service/src/com/android/car/AppFocusService.java b/service/src/com/android/car/AppFocusService.java
index 674d7ff..477529d 100644
--- a/service/src/com/android/car/AppFocusService.java
+++ b/service/src/com/android/car/AppFocusService.java
@@ -208,7 +208,9 @@
// ignore as listener doesn't own focus.
return;
}
- if (mFocusOwners.contains(appType)) {
+ // Because this code will run as part of unit tests on older platform, we can't use
+ // APIs such as {@link SparseArray#contains} that are added with API 30.
+ if (mFocusOwners.indexOfKey(appType) >= 0) {
mFocusOwners.remove(appType);
mActiveAppTypes.remove(appType);
info.removeOwnedAppType(appType);
@@ -278,7 +280,9 @@
*/
public boolean isFocusOwner(int uid, int pid, int appType) {
synchronized (mLock) {
- if (mFocusOwners.contains(appType)) {
+ // Because this code will run as part of unit tests on older platform, we can't use
+ // APIs such as {@link SparseArray#contains} that are added with API 30.
+ if (mFocusOwners.indexOfKey(appType) >= 0) {
OwnershipClientInfo clientInfo = mFocusOwners.get(appType);
return clientInfo.getUid() == uid && clientInfo.getPid() == pid;
}
diff --git a/service/src/com/android/car/CarOccupantZoneService.java b/service/src/com/android/car/CarOccupantZoneService.java
index a2bb991..7ba6929 100644
--- a/service/src/com/android/car/CarOccupantZoneService.java
+++ b/service/src/com/android/car/CarOccupantZoneService.java
@@ -48,8 +48,6 @@
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
-import android.util.Log;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Display;
@@ -192,9 +190,7 @@
@VisibleForTesting
final UserLifecycleListener mUserLifecycleListener = event -> {
- if (Log.isLoggable(CarLog.TAG_MEDIA, Log.DEBUG)) {
- Slog.d(CarLog.TAG_MEDIA, "onEvent(" + event + ")");
- }
+ Slogf.d(TAG, "onEvent(%s)", event);
if (CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING == event.getEventType()) {
handleUserChange();
}
@@ -296,17 +292,17 @@
for (int i = 0; i < mActiveOccupantConfigs.size(); ++i) {
OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
if (config.userId == userId && zoneId != mActiveOccupantConfigs.keyAt(i)) {
- Slog.w(TAG, "cannot assign user to two different zone simultaneously");
+ Slogf.w(TAG, "cannot assign user to two different zone simultaneously");
return false;
}
}
OccupantConfig zoneConfig = mActiveOccupantConfigs.get(zoneId);
if (zoneConfig == null) {
- Slog.w(TAG, "cannot find the zone(" + zoneId + ")");
+ Slogf.w(TAG, "cannot find the zone(%d)", zoneId);
return false;
}
if (zoneConfig.userId != UserHandle.USER_NULL && zoneConfig.userId != userId) {
- Slog.w(TAG, "other user already occupies the zone(" + zoneId + ")");
+ Slogf.w(TAG, "other user already occupies the zone(%d)", zoneId);
return false;
}
zoneConfig.userId = userId;
@@ -620,8 +616,8 @@
return mActiveOccupantConfigs.keyAt(i);
}
}
- Slog.w(TAG, "Could not find occupantZoneId for userId" + userId
- + " returning invalid occupant zone id " + OccupantZoneInfo.INVALID_ZONE_ID);
+ Slogf.w(TAG, "Could not find occupantZoneId for userId%d returning invalid "
+ + "occupant zone id %d", userId, OccupantZoneInfo.INVALID_ZONE_ID);
return OccupantZoneInfo.INVALID_ZONE_ID;
}
}
@@ -695,11 +691,11 @@
if (!mProfileUsers.contains(userId) && userId != UserHandle.USER_NULL) {
// current user can change while this call is happening, so return false rather
// than throwing exception
- Slog.w(TAG, "Invalid profile user id:" + userId);
+ Slogf.w(TAG, "Invalid profile user id: %d", userId);
return false;
}
if (!mUserManager.isUserRunning(userId)) {
- Slog.w(TAG, "User is not running:" + userId);
+ Slogf.w(TAG, "User%d is not running.", userId);
return false;
}
OccupantConfig config = mActiveOccupantConfigs.get(occupantZoneId);
@@ -707,8 +703,8 @@
throw new IllegalArgumentException("Invalid occupantZoneId:" + occupantZoneId);
}
if (config.userId == userId && userId != UserHandle.USER_NULL) {
- Slog.w(TAG, "assignProfileUserToOccupantZone zone:"
- + occupantZoneId + " already set to user:" + userId);
+ Slogf.w(TAG, "assignProfileUserToOccupantZone zone:%d already set to user:%",
+ occupantZoneId, userId);
return true;
}
if (userId == UserHandle.USER_NULL) {
@@ -785,7 +781,7 @@
try {
helper.setPassengerDisplays(passengerDisplayIds);
} catch (RemoteException e) {
- Slog.e(TAG, "ICarServiceHelper.setPassengerDisplays failed");
+ Slogf.e(TAG, "ICarServiceHelper.setPassengerDisplays failed", e);
}
}
@@ -794,16 +790,16 @@
ArrayList<ComponentName> componentNames = null;
if (components == null || components.length == 0) {
enableSourcePreferred = false;
- Slog.i(TAG, "CarLaunchParamsModifier: disable source-preferred");
+ Slogf.i(TAG, "CarLaunchParamsModifier: disable source-preferred");
} else if (components.length == 1 && components[0].equals(ALL_COMPONENTS)) {
enableSourcePreferred = true;
- Slog.i(TAG, "CarLaunchParamsModifier: enable source-preferred for all Components");
+ Slogf.i(TAG, "CarLaunchParamsModifier: enable source-preferred for all Components");
} else {
componentNames = new ArrayList<>((components.length));
for (String item : components) {
ComponentName name = ComponentName.unflattenFromString(item);
if (name == null) {
- Slog.e(TAG, "CarLaunchParamsModifier: Wrong ComponentName=" + item);
+ Slogf.e(TAG, "CarLaunchParamsModifier: Wrong ComponentName=" + item);
return;
}
componentNames.add(name);
@@ -815,7 +811,7 @@
mEnableSourcePreferred = enableSourcePreferred;
mSourcePreferredComponents = componentNames;
} catch (RemoteException e) {
- Slog.e(TAG, "ICarServiceHelper.setSourcePreferredComponents failed");
+ Slogf.e(TAG, "ICarServiceHelper.setSourcePreferredComponents failed");
}
}
@@ -854,7 +850,7 @@
helper.setDisplayAllowlistForUser(userId, allowlists.valueAt(i).toArray());
}
} catch (RemoteException e) {
- Slog.e(TAG, "ICarServiceHelper.setDisplayAllowlistForUser failed");
+ Slogf.e(TAG, "ICarServiceHelper.setDisplayAllowlistForUser failed", e);
}
}
@@ -975,7 +971,7 @@
if (!hasDriver) {
maxZoneId++;
mDriverZoneId = maxZoneId;
- Slog.w(TAG, "No driver zone, add one:" + mDriverZoneId);
+ Slogf.w(TAG, "No driver zone, add one:%d", mDriverZoneId);
OccupantZoneInfo info = new OccupantZoneInfo(mDriverZoneId,
CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER, getDriverSeat());
mOccupantsConfig.put(mDriverZoneId, info);
@@ -1099,7 +1095,7 @@
for (Display display : mDisplayManager.getDisplays()) {
DisplayConfig displayConfig = findDisplayConfigForDisplayLocked(display);
if (displayConfig == null) {
- Slogf.w(TAG, "Display id: %d does not have configurations",
+ Slogf.w(TAG, "Display id:%d does not have configurations",
display.getDisplayId());
continue;
}
@@ -1115,7 +1111,7 @@
}
if (!hasDefaultDisplayConfig) {
// Can reach here if default display has no port / no config
- Slog.w(TAG, "Default display not assigned, will assign to driver zone");
+ Slogf.w(TAG, "Default display not assigned, will assign to driver zone");
addDisplayInfoToOccupantZoneLocked(mDriverZoneId, new DisplayInfo(
mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY),
CarOccupantZoneManager.DISPLAY_TYPE_MAIN));
@@ -1149,8 +1145,8 @@
OccupantConfig config = mActiveOccupantConfigs.valueAt(i);
// mProfileUsers empty if not supported
if (mProfileUsers.contains(config.userId)) {
- Slog.i(TAG, "Profile user:" + config.userId
- + " already assigned for occupant zone:" + zoneId);
+ Slogf.i(TAG, "Profile user:%d already assigned for occupant zone:%d",
+ config.userId, zoneId);
} else {
config.userId = driverUserId;
}
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index ffa071e..6867ca5 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -236,6 +236,8 @@
PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_SET_GROUP_VOLUME,
PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
+ USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY,
+ android.Manifest.permission.INJECT_EVENTS);
}
private static final String PARAM_DAY_MODE = "day";
@@ -1030,9 +1032,14 @@
private void injectKeyEvent(int action, int keyCode, int display) {
long currentTime = SystemClock.uptimeMillis();
if (action == KeyEvent.ACTION_DOWN) mKeyDownTime = currentTime;
- mCarInputService.onKeyEvent(
- new KeyEvent(/* downTime= */ mKeyDownTime, /* eventTime= */ currentTime,
- action, keyCode, /* repeat= */ 0), display);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mCarInputService.injectKeyEvent(
+ new KeyEvent(/* downTime= */ mKeyDownTime, /* eventTime= */ currentTime,
+ action, keyCode, /* repeat= */ 0), display);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private void injectRotary(String[] args, IndentingPrintWriter writer) {
diff --git a/service/src/com/android/car/admin/CarDevicePolicyService.java b/service/src/com/android/car/admin/CarDevicePolicyService.java
index db7fe83..4425936 100644
--- a/service/src/com/android/car/admin/CarDevicePolicyService.java
+++ b/service/src/com/android/car/admin/CarDevicePolicyService.java
@@ -25,6 +25,8 @@
import android.car.admin.ICarDevicePolicyService;
import android.car.user.UserCreationResult;
import android.car.user.UserRemovalResult;
+import android.car.user.UserStartResult;
+import android.car.user.UserStopResult;
import android.content.pm.UserInfo;
import android.os.UserManager;
import android.sysprop.CarProperties;
@@ -102,6 +104,17 @@
}
@Override
+ public void startUserInBackground(@UserIdInt int userId,
+ AndroidFuture<UserStartResult> receiver) {
+ mCarUserService.startUserInBackground(userId, receiver);
+ }
+
+ @Override
+ public void stopUser(@UserIdInt int userId, AndroidFuture<UserStopResult> receiver) {
+ mCarUserService.stopUser(userId, receiver);
+ }
+
+ @Override
public void dump(@NonNull IndentingPrintWriter writer) {
checkHasDumpPermissionGranted("dump()");
diff --git a/service/src/com/android/car/cluster/ClusterHomeService.java b/service/src/com/android/car/cluster/ClusterHomeService.java
index 388b594..1cdc406 100644
--- a/service/src/com/android/car/cluster/ClusterHomeService.java
+++ b/service/src/com/android/car/cluster/ClusterHomeService.java
@@ -37,6 +37,7 @@
import android.content.pm.PackageManager;
import android.graphics.Insets;
import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.RemoteCallbackList;
@@ -44,8 +45,6 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
import android.view.Display;
import com.android.car.CarLog;
@@ -54,6 +53,7 @@
import com.android.car.R;
import com.android.car.am.FixedActivityService;
import com.android.car.hal.ClusterHalService;
+import com.android.server.utils.Slogf;
/**
* Service responsible for interactions between ClusterOS and ClusterHome.
@@ -65,8 +65,6 @@
private static final int DEFAULT_MIN_UPDATE_INTERVAL_MILLIS = 1000;
private static final String NAV_STATE_PROTO_BUNDLE_KEY = "navstate2";
- private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-
private final Context mContext;
private final ClusterHalService mClusterHalService;
private final ClusterNavigationService mClusterNavigationService;
@@ -79,8 +77,7 @@
private int mClusterDisplayId = Display.INVALID_DISPLAY;
private int mOnOff = DISPLAY_OFF;
- private int mWidth;
- private int mHeight;
+ private Rect mBounds = new Rect();
private Insets mInsets = Insets.NONE;
private int mUiType = ClusterHomeManager.UI_TYPE_CLUSTER_HOME;
private Intent mLastIntent;
@@ -104,14 +101,14 @@
@Override
public void init() {
- if (DBG) Slog.d(TAG, "initClusterHomeService");
+ Slogf.d(TAG, "initClusterHomeService");
if (TextUtils.isEmpty(mClusterHomeActivity.getPackageName())
|| TextUtils.isEmpty(mClusterHomeActivity.getClassName())) {
- Slog.i(TAG, "Improper ClusterHomeActivity: " + mClusterHomeActivity);
+ Slogf.i(TAG, "Improper ClusterHomeActivity: %s", mClusterHomeActivity);
return;
}
if (!mClusterHalService.isCoreSupported()) {
- Slog.e(TAG, "No Cluster HAL properties");
+ Slogf.e(TAG, "No Cluster HAL properties");
return;
}
@@ -127,7 +124,7 @@
int clusterDisplayId = mOccupantZoneService.getDisplayIdForDriver(
CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER);
if (clusterDisplayId == Display.INVALID_DISPLAY) {
- Slog.i(TAG, "No cluster display is defined");
+ Slogf.i(TAG, "No cluster display is defined");
}
if (clusterDisplayId == mClusterDisplayId) {
return; // Skip if the cluster display isn't changed.
@@ -137,18 +134,15 @@
return;
}
- // Initialize mWidth/mHeight only once.
- if (mWidth == 0 && mHeight == 0) {
+ // Initialize mBounds only once.
+ if (mBounds.right == 0 && mBounds.bottom == 0 && mBounds.left == 0 && mBounds.top == 0) {
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
Display clusterDisplay = displayManager.getDisplay(clusterDisplayId);
Point size = new Point();
clusterDisplay.getRealSize(size);
- mWidth = size.x;
- mHeight = size.y;
- if (DBG) {
- Slog.d(TAG, "Found cluster displayId=" + clusterDisplayId
- + ", width=" + mWidth + ", height=" + mHeight);
- }
+ mBounds.right = size.x;
+ mBounds.bottom = size.y;
+ Slogf.d(TAG, "Found cluster displayId=%d, bounds=%s", clusterDisplayId, mBounds);
}
ActivityOptions activityOptions = ActivityOptions.makeBasic()
@@ -169,7 +163,7 @@
@Override
public void release() {
- if (DBG) Slog.d(TAG, "releaseClusterHomeService");
+ Slogf.d(TAG, "releaseClusterHomeService");
mOccupantZoneService.unregisterCallback(mOccupantZoneCallback);
mClusterHalService.setCallback(null);
mClusterNavigationService.setClusterServiceCallback(null);
@@ -184,7 +178,7 @@
// ClusterHalEventListener starts
@Override
public void onSwitchUi(int uiType) {
- if (DBG) Slog.d(TAG, "onSwitchUi: uiType=" + uiType);
+ Slogf.d(TAG, "onSwitchUi: uiType=%d", uiType);
int changes = 0;
if (mUiType != uiType) {
mUiType = uiType;
@@ -204,20 +198,15 @@
}
@Override
- public void onDisplayState(int onOff, int width, int height, Insets insets) {
- if (DBG) {
- Slog.d(TAG, "onDisplayState: onOff=" + onOff + ", width=" + width
- + ", height=" + height + ", insets=" + insets);
- }
+ public void onDisplayState(int onOff, Rect bounds, Insets insets) {
+ Slogf.d(TAG, "onDisplayState: onOff=%d, bounds=%s, insets=%s", onOff, bounds, insets);
int changes = 0;
if (onOff != DONT_CARE && mOnOff != onOff) {
mOnOff = onOff;
changes |= ClusterHomeManager.CONFIG_DISPLAY_ON_OFF;
}
- if (width != DONT_CARE && height != DONT_CARE
- && (mWidth != width || mHeight != height)) {
- mWidth = width;
- mHeight = height;
+ if (bounds != null && !mBounds.equals(bounds)) {
+ mBounds = bounds;
changes |= ClusterHomeManager.CONFIG_DISPLAY_SIZE;
}
if (insets != null && !mInsets.equals(insets)) {
@@ -257,7 +246,7 @@
mClientCallbacks.finishBroadcast();
if (!mClusterHalService.isNavigationStateSupported()) {
- if (DBG) Slog.d(TAG, "No Cluster NavigationState HAL property");
+ Slogf.d(TAG, "No Cluster NavigationState HAL property");
return;
}
mClusterHalService.sendNavigationState(protoBytes);
@@ -277,17 +266,17 @@
// IClusterHomeService starts
@Override
public void reportState(int uiTypeMain, int uiTypeSub, byte[] uiAvailability) {
- if (DBG) Slog.d(TAG, "reportState: main=" + uiTypeMain + ", sub=" + uiTypeSub);
+ Slogf.d(TAG, "reportState: main=%d, sub=%d", uiTypeMain, uiTypeSub);
enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
- mClusterHalService.reportState(mOnOff, mWidth, mHeight, mInsets,
+ mClusterHalService.reportState(mOnOff, mBounds, mInsets,
uiTypeMain, uiTypeSub, uiAvailability);
}
@Override
public void requestDisplay(int uiType) {
- if (DBG) Slog.d(TAG, "requestDisplay: uiType=" + uiType);
+ Slogf.d(TAG, "requestDisplay: uiType=%d", uiType);
enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
@@ -300,7 +289,7 @@
enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
if (mClusterDisplayId == Display.INVALID_DISPLAY) {
- Slog.e(TAG, "Cluster display is not ready.");
+ Slogf.e(TAG, "Cluster display is not ready.");
return false;
}
@@ -316,7 +305,7 @@
enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
if (mClusterDisplayId == Display.INVALID_DISPLAY) {
- Slog.e(TAG, "Cluster display is not ready.");
+ Slogf.e(TAG, "Cluster display is not ready.");
return;
}
@@ -341,7 +330,7 @@
@Override
public ClusterState getClusterState() {
- if (DBG) Slog.d(TAG, "getClusterState");
+ Slogf.d(TAG, "getClusterState");
enforcePermission(Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
if (!mServiceEnabled) throw new IllegalStateException("Service is not enabled");
return createClusterState();
@@ -358,8 +347,7 @@
private ClusterState createClusterState() {
ClusterState state = new ClusterState();
state.on = mOnOff == DISPLAY_ON;
- state.width = mWidth;
- state.height = mHeight;
+ state.bounds = mBounds;
state.insets = mInsets;
state.uiType = mUiType;
return state;
diff --git a/service/src/com/android/car/hal/ClusterHalService.java b/service/src/com/android/car/hal/ClusterHalService.java
index c37d817..325b30d 100644
--- a/service/src/com/android/car/hal/ClusterHalService.java
+++ b/service/src/com/android/car/hal/ClusterHalService.java
@@ -24,15 +24,15 @@
import android.annotation.NonNull;
import android.graphics.Insets;
+import android.graphics.Rect;
import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.util.IntArray;
-import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.utils.Slogf;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -56,19 +56,22 @@
public interface ClusterHalEventCallback {
/**
* Called when CLUSTER_SWITCH_UI message is received.
+ *
* @param uiType uiType ClusterOS wants to switch to
*/
void onSwitchUi(int uiType);
/**
* Called when CLUSTER_DISPLAY_STATE message is received.
- * @param onOff 0 - off, 1 - on
- * @param width width in pixel
- * @param height height in pixel
+ *
+ * @param onOff 0 - off, 1 - on
+ * @param bounds the area to render the cluster Activity in pixel
* @param insets Insets of the cluster display
*/
- void onDisplayState(int onOff, int width, int height, Insets insets);
- };
+ void onDisplayState(int onOff, Rect bounds, Insets insets);
+ }
+
+ ;
private static final int[] SUPPORTED_PROPERTIES = new int[]{
CLUSTER_SWITCH_UI,
@@ -106,17 +109,17 @@
@Override
public void init() {
- if (DBG) Log.d(TAG, "initClusterHalService");
+ Slogf.d(TAG, "initClusterHalService");
if (!isCoreSupported()) return;
- for (int property: SUBSCRIBABLE_PROPERTIES) {
+ for (int property : SUBSCRIBABLE_PROPERTIES) {
mHal.subscribeProperty(this, property);
}
}
@Override
public void release() {
- if (DBG) Log.d(TAG, "releaseClusterHalService");
+ Slogf.d(TAG, "releaseClusterHalService");
synchronized (mLock) {
mCallback = null;
}
@@ -152,10 +155,8 @@
}
}
mIsNavigationStateSupported = supportedProperties.indexOf(CLUSTER_NAVIGATION_STATE) >= 0;
- if (DBG) {
- Log.d(TAG, "takeProperties: coreSupported=" + mIsCoreSupported
- + ", navigationStateSupported=" + mIsNavigationStateSupported);
- }
+ Slogf.d(TAG, "takeProperties: coreSupported=%s, navigationStateSupported=%s",
+ mIsCoreSupported, mIsNavigationStateSupported);
}
public boolean isCoreSupported() {
@@ -168,7 +169,7 @@
@Override
public void onHalEvents(List<VehiclePropValue> values) {
- if (DBG) Log.d(TAG, "handleHalEvents(): " + values);
+ Slogf.d(TAG, "handleHalEvents(): %s", values);
ClusterHalEventCallback callback;
synchronized (mLock) {
callback = mCallback;
@@ -183,22 +184,22 @@
break;
case CLUSTER_DISPLAY_STATE:
int onOff = value.value.int32Values.get(0);
- int width = DONT_CARE;
- int height = DONT_CARE;
- if (hasNoDontCare(value.value.int32Values, 1, 2, "width/height")) {
- width = value.value.int32Values.get(1);
- height = value.value.int32Values.get(2);
+ Rect bounds = null;
+ if (hasNoDontCare(value.value.int32Values, 1, 4, "bounds")) {
+ bounds = new Rect(
+ value.value.int32Values.get(1), value.value.int32Values.get(2),
+ value.value.int32Values.get(3), value.value.int32Values.get(4));
}
Insets insets = null;
- if (hasNoDontCare(value.value.int32Values, 3, 4, "insets")) {
+ if (hasNoDontCare(value.value.int32Values, 5, 4, "insets")) {
insets = Insets.of(
- value.value.int32Values.get(3), value.value.int32Values.get(4),
- value.value.int32Values.get(5), value.value.int32Values.get(6));
+ value.value.int32Values.get(5), value.value.int32Values.get(6),
+ value.value.int32Values.get(7), value.value.int32Values.get(8));
}
- callback.onDisplayState(onOff, width, height, insets);
+ callback.onDisplayState(onOff, bounds, insets);
break;
default:
- Slog.w(TAG, "received unsupported event from HAL: " + value);
+ Slogf.w(TAG, "received unsupported event from HAL: %s", value);
}
}
}
@@ -211,28 +212,30 @@
}
if (count == 0) return true;
if (count != length) {
- Slog.w(TAG, "Don't care should be set in the whole " + fieldName);
+ Slogf.w(TAG, "Don't care should be set in the whole %s.", fieldName);
}
return false;
}
/**
* Reports the current display state and ClusterUI state.
- * @param onOff 0 - off, 1 - on
- * @param width width in pixel
- * @param height height in pixel
- * @param insets Insets of the cluster display
- * @param uiTypeMain uiType that ClusterHome tries to show in main area
- * @param uiTypeSub uiType that ClusterHome tries to show in sub area
+ *
+ * @param onOff 0 - off, 1 - on
+ * @param bounds the area to render the cluster Activity in pixel
+ * @param insets Insets of the cluster display
+ * @param uiTypeMain uiType that ClusterHome tries to show in main area
+ * @param uiTypeSub uiType that ClusterHome tries to show in sub area
* @param uiAvailability the byte array to represent the availability of ClusterUI.
*/
- public void reportState(int onOff, int width, int height, Insets insets,
+ public void reportState(int onOff, Rect bounds, Insets insets,
int uiTypeMain, int uiTypeSub, byte[] uiAvailability) {
if (!isCoreSupported()) return;
VehiclePropValue request = createVehiclePropValue(CLUSTER_REPORT_STATE);
request.value.int32Values.add(onOff);
- request.value.int32Values.add(width);
- request.value.int32Values.add(height);
+ request.value.int32Values.add(bounds.left);
+ request.value.int32Values.add(bounds.top);
+ request.value.int32Values.add(bounds.right);
+ request.value.int32Values.add(bounds.bottom);
request.value.int32Values.add(insets.left);
request.value.int32Values.add(insets.top);
request.value.int32Values.add(insets.right);
@@ -245,6 +248,7 @@
/**
* Requests to turn the cluster display on to show some ClusterUI.
+ *
* @param uiType uiType that ClusterHome tries to show in main area
*/
public void requestDisplay(int uiType) {
@@ -257,6 +261,7 @@
/**
* Informs the current navigation state.
+ *
* @param navigateState the serialized message of {@code NavigationStateProto}
*/
public void sendNavigationState(byte[] navigateState) {
@@ -270,13 +275,13 @@
try {
mHal.set(request);
} catch (ServiceSpecificException e) {
- Slog.e(TAG, "Failed to send request: " + request, e);
+ Slogf.e(TAG, "Failed to send request: " + request, e);
}
}
private static void fillByteList(ArrayList<Byte> byteList, byte[] bytesArray) {
byteList.ensureCapacity(bytesArray.length);
- for (byte b: bytesArray) {
+ for (byte b : bytesArray) {
byteList.add(b);
}
}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 685a7ce..5439236 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -44,6 +44,8 @@
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
import android.car.user.UserRemovalResult;
+import android.car.user.UserStartResult;
+import android.car.user.UserStopResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.HalCallback;
import android.car.userlib.UserHalHelper;
@@ -110,6 +112,7 @@
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.UserIcons;
+import com.android.server.utils.Slogf;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -964,10 +967,10 @@
sendUserSwitchResult(receiver, UserSwitchResult.STATUS_NOT_SWITCHABLE);
return;
}
- mHandler.post(()-> switchUserInternal(targetUser, timeoutMs, receiver));
+ mHandler.post(() -> handleSwitchUser(targetUser, timeoutMs, receiver));
}
- private void switchUserInternal(@NonNull UserInfo targetUser, int timeoutMs,
+ private void handleSwitchUser(@NonNull UserInfo targetUser, int timeoutMs,
@NonNull AndroidFuture<UserSwitchResult> receiver) {
int currentUser = ActivityManager.getCurrentUser();
int targetUserId = targetUser.id;
@@ -1129,10 +1132,10 @@
+ " can only remove itself");
}
}
- mHandler.post(()-> removeUserInternal(userId, hasCallerRestrictions, receiver));
+ mHandler.post(() -> handleRemoveUser(userId, hasCallerRestrictions, receiver));
}
- private void removeUserInternal(@UserIdInt int userId, boolean hasCallerRestrictions,
+ private void handleRemoveUser(@UserIdInt int userId, boolean hasCallerRestrictions,
AndroidFuture<UserRemovalResult> receiver) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
if (userInfo == null) {
@@ -1301,12 +1304,12 @@
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_CREATE_USER_REQ,
UserHelperLite.safeName(name), userType, flags, timeoutMs,
hasCallerRestrictions ? 1 : 0);
- mHandler.post(() -> createUserInternal(name, userType, flags, timeoutMs, receiver,
+ mHandler.post(() -> handleCreateUser(name, userType, flags, timeoutMs, receiver,
hasCallerRestrictions));
}
- private void createUserInternal(@Nullable String name, @NonNull String userType,
+ private void handleCreateUser(@Nullable String name, @NonNull String userType,
@UserInfoFlag int flags, int timeoutMs,
@NonNull AndroidFuture<UserCreationResult> receiver,
boolean hasCallerRestrictions) {
@@ -1840,6 +1843,53 @@
}
/**
+ * Starts the specified user in the background.
+ *
+ * @param userId user to start in background
+ * @param receiver to post results
+ */
+ public void startUserInBackground(@UserIdInt int userId,
+ @NonNull AndroidFuture<UserStartResult> receiver) {
+ mHandler.post(() -> handleStartUserInBackground(userId, receiver));
+ }
+
+ private void handleStartUserInBackground(@UserIdInt int userId,
+ @NonNull AndroidFuture<UserStartResult> receiver) {
+ // If the requested user is the current user, do nothing and return success.
+ if (ActivityManager.getCurrentUser() == userId) {
+ sendUserStartResult(UserStartResult.STATUS_SUCCESSFUL_USER_IS_CURRENT_USER, receiver);
+ return;
+ }
+ // If requested user does not exist, return error.
+ if (mUserManager.getUserInfo(userId) == null) {
+ Slogf.w(TAG, "User %d does not exist", userId);
+ sendUserStartResult(UserStartResult.STATUS_USER_DOES_NOT_EXIST, receiver);
+ return;
+ }
+
+ try {
+ if (!mAm.startUserInBackground(userId)) {
+ Slogf.w(TAG, "Failed to start user %d in background", userId);
+ sendUserStartResult(UserStartResult.STATUS_ANDROID_FAILURE, receiver);
+ return;
+ }
+ } catch (RemoteException e) {
+ Slogf.w(TAG, e, "Failed to start user %d in background", userId);
+ }
+
+ // TODO(b/181331178): We are not updating mBackgroundUsersToRestart or
+ // mBackgroundUsersRestartedHere, which were only used for the garage mode. Consider
+ // renaming them to make it more clear.
+ sendUserStartResult(UserStartResult.STATUS_SUCCESSFUL, receiver);
+ }
+
+ private void sendUserStartResult(@UserStartResult.Status int result,
+ @NonNull AndroidFuture<UserStartResult> receiver) {
+ // TODO(b/181331178): Add event log calls.
+ receiver.complete(new UserStartResult(result));
+ }
+
+ /**
* Starts all background users that were active in system.
*
* @return list of background users started successfully.
@@ -1891,36 +1941,67 @@
}
/**
- * Stops all background users that were active in system.
+ * Stops the specified background user.
+ *
+ * @param userId user to stop
+ * @param receiver to post results
+ */
+ public void stopUser(@UserIdInt int userId, @NonNull AndroidFuture<UserStopResult> receiver) {
+ mHandler.post(() -> handleStopUser(userId, receiver));
+ }
+
+ private void handleStopUser(
+ @UserIdInt int userId, @NonNull AndroidFuture<UserStopResult> receiver) {
+ @UserStopResult.Status int userStopStatus = stopBackgroundUserInternal(userId);
+ sendUserStopResult(userStopStatus, receiver);
+ }
+
+ private void sendUserStopResult(@UserStopResult.Status int result,
+ @NonNull AndroidFuture<UserStopResult> receiver) {
+ // TODO(b/181331178): Add event log calls.
+ receiver.complete(new UserStopResult(result));
+ }
+
+ private @UserStopResult.Status int stopBackgroundUserInternal(@UserIdInt int userId) {
+ try {
+ int r = mAm.stopUserWithDelayedLocking(userId, true, null);
+ switch(r) {
+ case ActivityManager.USER_OP_SUCCESS:
+ return UserStopResult.STATUS_SUCCESSFUL;
+ case ActivityManager.USER_OP_ERROR_IS_SYSTEM:
+ Slogf.w(TAG, "Cannot stop the system user: %d", userId);
+ return UserStopResult.STATUS_FAILURE_SYSTEM_USER;
+ case ActivityManager.USER_OP_IS_CURRENT:
+ Slogf.w(TAG, "Cannot stop the current user: %d", userId);
+ return UserStopResult.STATUS_FAILURE_CURRENT_USER;
+ case ActivityManager.USER_OP_UNKNOWN_USER:
+ Slogf.w(TAG, "Cannot stop the user that does not exist: %d", userId);
+ return UserStopResult.STATUS_USER_DOES_NOT_EXIST;
+ default:
+ Slogf.w(TAG, "stopUser failed, user: %d, err: %d", userId, r);
+ }
+ } catch (RemoteException e) {
+ // ignore the exception
+ Slogf.w(TAG, e, "error while stopping user: %d", userId);
+ }
+ return UserStopResult.STATUS_ANDROID_FAILURE;
+ }
+
+ /**
+ * Stops a background user.
*
* @return whether stopping succeeds.
*/
public boolean stopBackgroundUser(@UserIdInt int userId) {
- if (userId == UserHandle.USER_SYSTEM) {
- return false;
- }
- if (userId == ActivityManager.getCurrentUser()) {
- Slog.i(TAG, "stopBackgroundUser, already a FG user:" + userId);
- return false;
- }
- try {
- int r = mAm.stopUserWithDelayedLocking(userId, true, null);
- if (r == ActivityManager.USER_OP_SUCCESS) {
- synchronized (mLockUser) {
- Integer user = userId;
- mBackgroundUsersRestartedHere.remove(user);
- }
- } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
- return false;
- } else {
- Slog.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
- return false;
+ @UserStopResult.Status int userStopStatus = stopBackgroundUserInternal(userId);
+ if (UserStopResult.isSuccess(userStopStatus)) {
+ // Remove the stopped user from the mBackgroundUserRestartedHere list.
+ synchronized (mLockUser) {
+ mBackgroundUsersRestartedHere.remove(Integer.valueOf(userId));
}
- } catch (RemoteException e) {
- // ignore
- Slog.w(TAG, "error while stopping user", e);
+ return true;
}
- return true;
+ return false;
}
/**
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 8b650ed..0b26e0a 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -63,8 +63,8 @@
* Service to implement CarWatchdogManager API.
*/
public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase {
- private static final boolean DEBUG = false; // STOPSHIP if true
- private static final String TAG = CarLog.tagFor(CarWatchdogService.class);
+ static final boolean DEBUG = false; // STOPSHIP if true
+ static final String TAG = CarLog.tagFor(CarWatchdogService.class);
private final Context mContext;
private final ICarWatchdogServiceForSystemImpl mWatchdogServiceForSystem;
@@ -85,9 +85,9 @@
mCarWatchdogDaemonHelper = new CarWatchdogDaemonHelper(TAG_WATCHDOG);
mWatchdogServiceForSystem = new ICarWatchdogServiceForSystemImpl(this);
mWatchdogProcessHandler = new WatchdogProcessHandler(mWatchdogServiceForSystem,
- mCarWatchdogDaemonHelper, DEBUG);
+ mCarWatchdogDaemonHelper);
mWatchdogPerfHandler = new WatchdogPerfHandler(mContext, mCarWatchdogDaemonHelper,
- mPackageInfoHandler, DEBUG);
+ mPackageInfoHandler);
}
@Override
diff --git a/service/src/com/android/car/watchdog/PackageInfoHandler.java b/service/src/com/android/car/watchdog/PackageInfoHandler.java
index c2b3323..f04f2b9 100644
--- a/service/src/com/android/car/watchdog/PackageInfoHandler.java
+++ b/service/src/com/android/car/watchdog/PackageInfoHandler.java
@@ -45,6 +45,8 @@
/* Cache of uid to package name mapping. */
@GuardedBy("mLock")
private final SparseArray<String> mPackageNamesByUid = new SparseArray<>();
+ @GuardedBy("mLock")
+ private List<String> mVendorPackagePrefixes = new ArrayList<>();
public PackageInfoHandler(PackageManager packageManager) {
mPackageManager = packageManager;
@@ -93,25 +95,31 @@
*/
public List<PackageInfo> getPackageInfosForUids(int[] uids,
List<String> vendorPackagePrefixes) {
+ synchronized (mLock) {
+ /*
+ * Vendor package prefixes don't change frequently because it changes only when the
+ * vendor configuration is updated. Thus caching this locally during this call should
+ * keep the cache up-to-date because the daemon issues this call frequently.
+ */
+ mVendorPackagePrefixes = vendorPackagePrefixes;
+ }
SparseArray<String> packageNamesByUid = getPackageNamesForUids(uids);
ArrayList<PackageInfo> packageInfos = new ArrayList<>(packageNamesByUid.size());
for (int i = 0; i < packageNamesByUid.size(); ++i) {
packageInfos.add(getPackageInfo(packageNamesByUid.keyAt(i),
- packageNamesByUid.valueAt(i), vendorPackagePrefixes));
+ packageNamesByUid.valueAt(i)));
}
return packageInfos;
}
- private PackageInfo getPackageInfo(
- int uid, String packageName, List<String> vendorPackagePrefixes) {
+ private PackageInfo getPackageInfo(int uid, String packageName) {
PackageInfo packageInfo = new PackageInfo();
packageInfo.packageIdentifier = new PackageIdentifier();
packageInfo.packageIdentifier.uid = uid;
packageInfo.packageIdentifier.name = packageName;
packageInfo.sharedUidPackages = new ArrayList<>();
packageInfo.componentType = ComponentType.UNKNOWN;
- // TODO(b/170741935): Identify application category type using the package names. Vendor
- // should define the mappings from package name to the application category type.
+ /* Application category type mapping is handled on the daemon side. */
packageInfo.appCategoryType = ApplicationCategoryType.OTHERS;
int userId = UserHandle.getUserId(uid);
int appId = UserHandle.getAppId(uid);
@@ -126,14 +134,13 @@
boolean seenVendor = false;
boolean seenSystem = false;
boolean seenThirdParty = false;
- /**
+ /*
* A shared UID has multiple packages associated with it and these packages may be
* mapped to different component types. Thus map the shared UID to the most restrictive
* component type.
*/
for (int i = 0; i < sharedUidPackages.length; ++i) {
- int componentType = getPackageComponentType(userId, sharedUidPackages[i],
- vendorPackagePrefixes);
+ int componentType = getPackageComponentType(userId, sharedUidPackages[i]);
switch(componentType) {
case ComponentType.VENDOR:
seenVendor = true;
@@ -159,35 +166,41 @@
}
} else {
packageInfo.componentType = getPackageComponentType(
- userId, packageName, vendorPackagePrefixes);
+ userId, packageName);
}
return packageInfo;
}
- private int getPackageComponentType(
- int userId, String packageName, List<String> vendorPackagePrefixes) {
+ private int getPackageComponentType(int userId, String packageName) {
try {
ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(packageName,
/* flags= */ 0, userId);
- if ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0
- || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0
- || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
- return ComponentType.VENDOR;
- }
- if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0
- || (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
- || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0
- || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) {
- for (String prefix : vendorPackagePrefixes) {
+ return getComponentType(packageName, info);
+ } catch (PackageManager.NameNotFoundException e) {
+ Slogf.e(TAG, "Package '%s' not found for user %d: %s", packageName, userId, e);
+ }
+ return ComponentType.UNKNOWN;
+ }
+
+ /** Returns the component type for the given package and its application info. */
+ public int getComponentType(String packageName, ApplicationInfo info) {
+ if ((info.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0
+ || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0
+ || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
+ return ComponentType.VENDOR;
+ }
+ if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+ || (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
+ || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0
+ || (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0) {
+ synchronized (mLock) {
+ for (String prefix : mVendorPackagePrefixes) {
if (packageName.startsWith(prefix)) {
return ComponentType.VENDOR;
}
}
- return ComponentType.SYSTEM;
}
- } catch (PackageManager.NameNotFoundException e) {
- Slogf.e(TAG, "Package '%s' not found for user %d: %s", packageName, userId, e);
- return ComponentType.UNKNOWN;
+ return ComponentType.SYSTEM;
}
return ComponentType.THIRD_PARTY;
}
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index 37fbbb3..80dcb82 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -34,11 +34,18 @@
import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.automotive.watchdog.ResourceType;
+import android.automotive.watchdog.internal.ApplicationCategoryType;
+import android.automotive.watchdog.internal.ComponentType;
import android.automotive.watchdog.internal.PackageIdentifier;
import android.automotive.watchdog.internal.PackageIoOveruseStats;
+import android.automotive.watchdog.internal.PackageMetadata;
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
+import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
+import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
import android.car.watchdog.CarWatchdogManager;
import android.car.watchdog.IResourceOveruseListener;
+import android.car.watchdog.IoOveruseAlertThreshold;
+import android.car.watchdog.IoOveruseConfiguration;
import android.car.watchdog.IoOveruseStats;
import android.car.watchdog.PackageKillableState;
import android.car.watchdog.PackageKillableState.KillableState;
@@ -48,18 +55,21 @@
import android.car.watchdoglib.CarWatchdogDaemonHelper;
import android.content.Context;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
-import com.android.car.CarLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -78,9 +88,10 @@
* Handles system resource performance monitoring module.
*/
public final class WatchdogPerfHandler {
- private static final String TAG = CarLog.tagFor(CarWatchdogService.class);
+ public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS = "MAPS";
+ public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA = "MEDIA";
+ public static final String INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN = "UNKNOWN";
- private final boolean mIsDebugEnabled;
private final Context mContext;
private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
private final PackageInfoHandler mPackageInfoHandler;
@@ -102,10 +113,15 @@
new SparseArray<>();
@GuardedBy("mLock")
private ZonedDateTime mLastStatsReportUTC;
+ /* Set of safe-to-kill system and vendor packages. */
+ @GuardedBy("mLock")
+ public final Set<String> mSafeToKillPackages = new ArraySet<>();
+ /* Default killable state for packages when not updated by the user. */
+ @GuardedBy("mLock")
+ public final Set<String> mDefaultNotKillablePackages = new ArraySet<>();
public WatchdogPerfHandler(Context context, CarWatchdogDaemonHelper daemonHelper,
- PackageInfoHandler packageInfoHandler, boolean isDebugEnabled) {
- mIsDebugEnabled = isDebugEnabled;
+ PackageInfoHandler packageInfoHandler) {
mContext = context;
mCarWatchdogDaemonHelper = daemonHelper;
mPackageInfoHandler = packageInfoHandler;
@@ -119,31 +135,31 @@
* TODO(b/183947162): Opt-in to receive package change broadcast and handle package enabled
* state changes.
*
- * TODO(b/170741935): Read the current day's I/O overuse stats from database and push them
+ * TODO(b/185287136): Persist in-memory data:
+ * 1. Read the current day's I/O overuse stats from database and push them
* to the daemon.
+ * 2. Fetch the safe-to-kill from daemon on initialization and update mSafeToKillPackages.
*/
synchronized (mLock) {
checkAndHandleDateChangeLocked();
}
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "WatchdogPerfHandler is initialized");
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "WatchdogPerfHandler is initialized");
}
}
/** Releases the handler */
public void release() {
- /*
- * TODO(b/170741935): Write daily usage to SQLite DB storage.
- */
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "WatchdogPerfHandler is released");
+ /* TODO(b/185287136): Write daily usage to SQLite DB storage. */
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "WatchdogPerfHandler is released");
}
}
/** Dumps its state. */
public void dump(IndentingPrintWriter writer) {
- /**
- * TODO(b/170741935): Implement this method.
+ /*
+ * TODO(b/183436216): Implement this method.
*/
}
@@ -156,9 +172,29 @@
"Must provide valid resource overuse flag");
Preconditions.checkArgument((maxStatsPeriod > 0),
"Must provide valid maximum stats period");
- // TODO(b/170741935): Implement this method.
- return new ResourceOveruseStats.Builder("",
- UserHandle.getUserHandleForUid(Binder.getCallingUid())).build();
+ // When more resource stats are added, make this as optional.
+ Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
+ "Must provide resource I/O overuse flag");
+ int callingUid = Binder.getCallingUid();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ UserHandle callingUserHandle = UserHandle.of(callingUserId);
+ String callingPackageName =
+ mPackageInfoHandler.getPackageNamesForUids(new int[]{callingUid})
+ .get(callingUid, null);
+ if (callingPackageName == null) {
+ Slogf.w(CarWatchdogService.TAG, "Failed to fetch package info for uid %d", callingUid);
+ return new ResourceOveruseStats.Builder("", callingUserHandle).build();
+ }
+ ResourceOveruseStats.Builder statsBuilder =
+ new ResourceOveruseStats.Builder(callingPackageName, callingUserHandle);
+ statsBuilder.setIoOveruseStats(getIoOveruseStats(callingUserId, callingPackageName,
+ /* minimumBytesWritten= */ 0, maxStatsPeriod));
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Returning all resource overuse stats for calling uid "
+ + "%d [user %d and package '%s']", callingUid, callingUserId,
+ callingPackageName);
+ }
+ return statsBuilder.build();
}
/** Returns resource overuse stats for all packages. */
@@ -171,8 +207,24 @@
"Must provide valid resource overuse flag");
Preconditions.checkArgument((maxStatsPeriod > 0),
"Must provide valid maximum stats period");
- // TODO(b/170741935): Implement this method.
- return new ArrayList<>();
+ // When more resource types are added, make this as optional.
+ Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
+ "Must provide resource I/O overuse flag");
+ long minimumBytesWritten = getMinimumBytesWritten(minimumStatsFlag);
+ List<ResourceOveruseStats> allStats = new ArrayList<>();
+ for (PackageResourceUsage usage : mUsageByUserPackage.values()) {
+ ResourceOveruseStats.Builder statsBuilder = usage.getResourceOveruseStatsBuilder();
+ IoOveruseStats ioOveruseStats = getIoOveruseStats(usage.userId, usage.packageName,
+ minimumBytesWritten, maxStatsPeriod);
+ if (ioOveruseStats == null) {
+ continue;
+ }
+ allStats.add(statsBuilder.setIoOveruseStats(ioOveruseStats).build());
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Returning all resource overuse stats");
+ }
+ return allStats;
}
/** Returns resource overuse stats for the specified user package. */
@@ -183,12 +235,25 @@
@CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
Objects.requireNonNull(packageName, "Package name must be non-null");
Objects.requireNonNull(userHandle, "User handle must be non-null");
+ Preconditions.checkArgument((userHandle != UserHandle.ALL),
+ "Must provide the user handle for a specific user");
Preconditions.checkArgument((resourceOveruseFlag > 0),
"Must provide valid resource overuse flag");
Preconditions.checkArgument((maxStatsPeriod > 0),
"Must provide valid maximum stats period");
- // TODO(b/170741935): Implement this method.
- return new ResourceOveruseStats.Builder("", userHandle).build();
+ // When more resource types are added, make this as optional.
+ Preconditions.checkArgument((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0,
+ "Must provide resource I/O overuse flag");
+ ResourceOveruseStats.Builder statsBuilder =
+ new ResourceOveruseStats.Builder(packageName, userHandle);
+ statsBuilder.setIoOveruseStats(getIoOveruseStats(userHandle.getIdentifier(), packageName,
+ /* minimumBytesWritten= */ 0, maxStatsPeriod));
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG,
+ "Returning resource overuse stats for user %d, package '%s'",
+ userHandle.getIdentifier(), packageName);
+ }
+ return statsBuilder.build();
}
/** Adds the resource overuse listener. */
@@ -238,18 +303,107 @@
boolean isKillable) {
Objects.requireNonNull(packageName, "Package name must be non-null");
Objects.requireNonNull(userHandle, "User handle must be non-null");
- /*
- * TODO(b/170741935): Add/remove the package from the user do-no-kill list.
- * If the {@code userHandle == UserHandle.ALL}, update the settings for all users.
- */
+ if (userHandle == UserHandle.ALL) {
+ synchronized (mLock) {
+ for (PackageResourceUsage usage : mUsageByUserPackage.values()) {
+ if (!usage.packageName.equals(packageName)) {
+ continue;
+ }
+ if (!usage.setKillableState(isKillable)) {
+ Slogf.e(CarWatchdogService.TAG,
+ "Cannot set killable state for package '%s'", packageName);
+ throw new IllegalArgumentException(
+ "Package killable state is not updatable");
+ }
+ }
+ if (!isKillable) {
+ mDefaultNotKillablePackages.add(packageName);
+ } else {
+ mDefaultNotKillablePackages.remove(packageName);
+ }
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG,
+ "Successfully set killable package state for all users");
+ }
+ return;
+ }
+ int userId = userHandle.getIdentifier();
+ String key = getUserPackageUniqueId(userId, packageName);
+ synchronized (mLock) {
+ /*
+ * When the queried package is not cached in {@link mUsageByUserPackage}, the set API
+ * will update the killable state even when the package should never be killed.
+ * But the get API will return the correct killable state. This behavior is tolerable
+ * because in production the set API should be called only after the get API.
+ * For instance, when this case happens by mistake and the package overuses resource
+ * between the set and the get API calls, the daemon will provide correct killable
+ * state when pushing the latest stats. Ergo, the invalid killable state doesn't have
+ * any effect.
+ */
+ PackageResourceUsage usage = mUsageByUserPackage.getOrDefault(key,
+ new PackageResourceUsage(userId, packageName));
+ if (!usage.setKillableState(isKillable)) {
+ Slogf.e(CarWatchdogService.TAG,
+ "User %d cannot set killable state for package '%s'",
+ userHandle.getIdentifier(), packageName);
+ throw new IllegalArgumentException("Package killable state is not updatable");
+ }
+ mUsageByUserPackage.put(key, usage);
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Successfully set killable package state for user %d",
+ userId);
+ }
}
/** Returns the list of package killable states on resource overuse for the user. */
@NonNull
public List<PackageKillableState> getPackageKillableStatesAsUser(UserHandle userHandle) {
Objects.requireNonNull(userHandle, "User handle must be non-null");
- // TODO(b/170741935): Implement this method.
- return new ArrayList<>();
+ PackageManager pm = mContext.getPackageManager();
+ if (userHandle != UserHandle.ALL) {
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Returning all package killable states for user %d",
+ userHandle.getIdentifier());
+ }
+ return getPackageKillableStatesForUserId(userHandle.getIdentifier(), pm);
+ }
+ List<PackageKillableState> packageKillableStates = new ArrayList<>();
+ UserManager userManager = UserManager.get(mContext);
+ List<UserInfo> userInfos = userManager.getAliveUsers();
+ for (UserInfo userInfo : userInfos) {
+ packageKillableStates.addAll(getPackageKillableStatesForUserId(userInfo.id, pm));
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Returning all package killable states for all users");
+ }
+ return packageKillableStates;
+ }
+
+ private List<PackageKillableState> getPackageKillableStatesForUserId(int userId,
+ PackageManager pm) {
+ List<PackageInfo> packageInfos = pm.getInstalledPackagesAsUser(/* flags= */0, userId);
+ List<PackageKillableState> states = new ArrayList<>();
+ synchronized (mLock) {
+ for (int i = 0; i < packageInfos.size(); ++i) {
+ PackageInfo packageInfo = packageInfos.get(i);
+ String key = getUserPackageUniqueId(userId, packageInfo.packageName);
+ PackageResourceUsage usage = mUsageByUserPackage.getOrDefault(key,
+ new PackageResourceUsage(userId, packageInfo.packageName));
+ int killableState = usage.syncAndFetchKillableStateLocked(
+ mPackageInfoHandler.getComponentType(packageInfo.packageName,
+ packageInfo.applicationInfo));
+ mUsageByUserPackage.put(key, usage);
+ states.add(
+ new PackageKillableState(packageInfo.packageName, userId, killableState));
+ }
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG,
+ "Returning the package killable states for a user package");
+ }
+ return states;
}
/** Sets the given resource overuse configurations. */
@@ -257,11 +411,18 @@
List<ResourceOveruseConfiguration> configurations,
@CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
Objects.requireNonNull(configurations, "Configurations must be non-null");
+ Preconditions.checkArgument((configurations.size() > 0),
+ "Must provide at least one configuration");
Preconditions.checkArgument((resourceOveruseFlag > 0),
"Must provide valid resource overuse flag");
Set<Integer> seenComponentTypes = new ArraySet<>();
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
+ new ArrayList<>();
for (ResourceOveruseConfiguration config : configurations) {
int componentType = config.getComponentType();
+ if (toComponentTypeStr(componentType).equals("UNKNOWN")) {
+ throw new IllegalArgumentException("Invalid component type in the configuration");
+ }
if (seenComponentTypes.contains(componentType)) {
throw new IllegalArgumentException(
"Cannot provide duplicate configurations for the same component type");
@@ -271,8 +432,24 @@
throw new IllegalArgumentException("Must provide I/O overuse configuration");
}
seenComponentTypes.add(config.getComponentType());
+ internalConfigs.add(toInternalResourceOveruseConfiguration(config,
+ resourceOveruseFlag));
}
- // TODO(b/170741935): Implement this method.
+
+ // TODO(b/186119640): Add retry logic when daemon is not available.
+ try {
+ mCarWatchdogDaemonHelper.updateResourceOveruseConfigurations(internalConfigs);
+ } catch (IllegalArgumentException e) {
+ Slogf.w(CarWatchdogService.TAG, "Failed to set resource overuse configurations: %s", e);
+ throw e;
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(CarWatchdogService.TAG, "Failed to set resource overuse configurations: %s", e);
+ throw new IllegalStateException(e);
+ }
+ /* TODO(b/185287136): Fetch safe-to-kill list from daemon and update mSafeToKillPackages. */
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Set the resource overuse configuration successfully");
+ }
}
/** Returns the available resource overuse configurations. */
@@ -281,8 +458,25 @@
@CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
Preconditions.checkArgument((resourceOveruseFlag > 0),
"Must provide valid resource overuse flag");
- // TODO(b/170741935): Implement this method.
- return new ArrayList<>();
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration> internalConfigs =
+ new ArrayList<>();
+ // TODO(b/186119640): Add retry logic when daemon is not available.
+ try {
+ internalConfigs = mCarWatchdogDaemonHelper.getResourceOveruseConfigurations();
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(CarWatchdogService.TAG, "Failed to fetch resource overuse configurations: %s",
+ e);
+ throw new IllegalStateException(e);
+ }
+ List<ResourceOveruseConfiguration> configs = new ArrayList<>();
+ for (android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig
+ : internalConfigs) {
+ configs.add(toResourceOveruseConfiguration(internalConfig, resourceOveruseFlag));
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Returning the resource overuse configuration");
+ }
+ return configs;
}
/** Processes the latest I/O overuse stats */
@@ -308,9 +502,12 @@
* and only the daemon is aware of such packages. Thus the flag is used to
* indicate which packages should be notified.
*/
- notifyResourceOveruseStatsLocked(stats.uid,
- usage.getResourceOveruseStatsWithIo());
+ ResourceOveruseStats resourceOveruseStats =
+ usage.getResourceOveruseStatsBuilder().setIoOveruseStats(
+ usage.getIoOveruseStats()).build();
+ notifyResourceOveruseStatsLocked(stats.uid, resourceOveruseStats);
}
+
if (!usage.ioUsage.exceedsThreshold()) {
continue;
}
@@ -326,7 +523,6 @@
* #2 The package has no recurring overuse behavior and the user opted to not
* kill the package so honor the user's decision.
*/
- String userPackageId = getUserPackageUniqueId(userId, packageName);
int killableState = usage.getKillableState();
if (killableState == KILLABLE_STATE_NEVER) {
mOveruseActionsByUserPackage.add(overuseAction);
@@ -363,8 +559,8 @@
usage.oldEnabledState = oldEnabledState;
}
} catch (RemoteException e) {
- Slogf.e(TAG, "Failed to disable application enabled setting for user %d, "
- + "package '%s'", userId, packageName);
+ Slogf.e(CarWatchdogService.TAG, "Failed to disable application enabled setting "
+ + "for user %d, package '%s'", userId, packageName);
}
mOveruseActionsByUserPackage.add(overuseAction);
}
@@ -373,6 +569,9 @@
WatchdogPerfHandler::notifyActionsTakenOnOveruse, this));
}
}
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Processed latest I/O overuse stats");
+ }
}
/** Notify daemon about the actions take on resource overuse */
@@ -387,9 +586,13 @@
}
try {
mCarWatchdogDaemonHelper.actionTakenOnResourceOveruse(actions);
- } catch (RemoteException e) {
- Slogf.w(TAG, "Failed to notify car watchdog daemon of actions taken on "
- + "resource overuse: %s", e);
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(CarWatchdogService.TAG, "Failed to notify car watchdog daemon of actions taken "
+ + "on resource overuse: %s", e);
+ }
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG,
+ "Notified car watchdog daemon of actions taken on resource overuse");
}
}
@@ -401,7 +604,7 @@
try {
listenerInfo.listener.onOveruse(resourceOveruseStats);
} catch (RemoteException e) {
- Slogf.e(TAG,
+ Slogf.e(CarWatchdogService.TAG,
"Failed to notify listener(uid %d, package '%s') on resource overuse: %s",
uid, resourceOveruseStats, e);
}
@@ -415,11 +618,15 @@
try {
systemListenerInfo.listener.onOveruse(resourceOveruseStats);
} catch (RemoteException e) {
- Slogf.e(TAG, "Failed to notify system listener(uid %d, pid: %d) of resource "
- + "overuse by package(uid %d, package '%s'): %s",
+ Slogf.e(CarWatchdogService.TAG, "Failed to notify system listener(uid %d, pid: %d) "
+ + "of resource overuse by package(uid %d, package '%s'): %s",
systemListenerInfo.uid, systemListenerInfo.pid, uid, packageName, e);
}
}
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG,
+ "Notified resource overuse stats to listening applications");
+ }
}
private void checkAndHandleDateChangeLocked() {
@@ -443,7 +650,7 @@
usage.oldEnabledState,
/* flags= */ 0, usage.userId, mContext.getPackageName());
} catch (RemoteException e) {
- Slogf.e(TAG,
+ Slogf.e(CarWatchdogService.TAG,
"Failed to reset enabled setting for disabled package '%s', user %d",
usage.packageName, usage.userId);
}
@@ -451,6 +658,9 @@
/* TODO(b/170741935): Stash the old usage into SQLite DB storage. */
usage.ioUsage.clear();
}
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Handled date change successfully");
+ }
}
private PackageResourceUsage cacheAndFetchUsageLocked(@UserIdInt int userId, String packageName,
@@ -458,19 +668,39 @@
String key = getUserPackageUniqueId(userId, packageName);
PackageResourceUsage usage = mUsageByUserPackage.getOrDefault(key,
new PackageResourceUsage(userId, packageName));
- usage.update(internalStats);
+ usage.updateLocked(internalStats);
mUsageByUserPackage.put(key, usage);
return usage;
}
private boolean isRecurringOveruseLocked(PackageResourceUsage ioUsage) {
/*
- * TODO(b/170741935): Look up I/O overuse history and determine whether or not the package
+ * TODO(b/185287136): Look up I/O overuse history and determine whether or not the package
* has recurring I/O overuse behavior.
*/
return false;
}
+ private IoOveruseStats getIoOveruseStats(int userId, String packageName,
+ long minimumBytesWritten, @CarWatchdogManager.StatsPeriod int maxStatsPeriod) {
+ String key = getUserPackageUniqueId(userId, packageName);
+ PackageResourceUsage usage = mUsageByUserPackage.get(key);
+ if (usage == null) {
+ return null;
+ }
+ IoOveruseStats stats = usage.getIoOveruseStats();
+ long totalBytesWritten = stats != null ? stats.getTotalBytesWritten() : 0;
+ /*
+ * TODO(b/185431129): When maxStatsPeriod > current day, populate the historical stats
+ * from the local database. Also handle the case where the package doesn't have current
+ * day stats but has historical stats.
+ */
+ if (totalBytesWritten < minimumBytesWritten) {
+ return null;
+ }
+ return stats;
+ }
+
private void addResourceOveruseListenerLocked(
@CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
@NonNull IResourceOveruseListener listener,
@@ -495,20 +725,21 @@
try {
listenerInfo.linkToDeath();
} catch (RemoteException e) {
- Slogf.w(TAG, "Cannot add %s: linkToDeath to listener failed", listenerType);
+ Slogf.w(CarWatchdogService.TAG, "Cannot add %s: linkToDeath to listener failed",
+ listenerType);
return;
}
if (existingListenerInfo != null) {
- Slogf.w(TAG, "Overwriting existing %s: pid %d, uid: %d", listenerType,
- existingListenerInfo.pid, existingListenerInfo.uid);
+ Slogf.w(CarWatchdogService.TAG, "Overwriting existing %s: pid %d, uid: %d",
+ listenerType, existingListenerInfo.pid, existingListenerInfo.uid);
existingListenerInfo.unlinkToDeath();
}
listenerInfosByUid.put(callingUid, listenerInfo);
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
callingPid, callingUid);
}
}
@@ -522,14 +753,15 @@
ResourceOveruseListenerInfo listenerInfo = listenerInfosByUid.get(callingUid, null);
if (listenerInfo == null || listenerInfo.listener != listener) {
- Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
+ Slogf.w(CarWatchdogService.TAG,
+ "Cannot remove the %s: it has not been registered before", listenerType);
return;
}
listenerInfo.unlinkToDeath();
listenerInfosByUid.remove(callingUid);
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType, listenerInfo.pid,
- listenerInfo.uid);
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "The %s (pid: %d, uid: %d) is removed", listenerType,
+ listenerInfo.pid, listenerInfo.uid);
}
}
@@ -561,9 +793,8 @@
private static PerStateBytes toPerStateBytes(
android.automotive.watchdog.PerStateBytes internalPerStateBytes) {
- PerStateBytes perStateBytes = new PerStateBytes(internalPerStateBytes.foregroundBytes,
+ return new PerStateBytes(internalPerStateBytes.foregroundBytes,
internalPerStateBytes.backgroundBytes, internalPerStateBytes.garageModeBytes);
- return perStateBytes;
}
private static long totalPerStateBytes(
@@ -575,7 +806,231 @@
internalPerStateBytes.backgroundBytes), internalPerStateBytes.garageModeBytes);
}
- private static final class PackageResourceUsage {
+ private static long getMinimumBytesWritten(
+ @CarWatchdogManager.MinimumStatsFlag int minimumStatsIoFlag) {
+ switch (minimumStatsIoFlag) {
+ case 0:
+ return 0;
+ case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB:
+ return 1024 * 1024;
+ case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_100_MB:
+ return 100 * 1024 * 1024;
+ case CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_GB:
+ return 1024 * 1024 * 1024;
+ default:
+ throw new IllegalArgumentException(
+ "Must provide valid minimum stats flag for I/O resource");
+ }
+ }
+
+ private static android.automotive.watchdog.internal.ResourceOveruseConfiguration
+ toInternalResourceOveruseConfiguration(ResourceOveruseConfiguration config,
+ @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig =
+ new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+ internalConfig.componentType = config.getComponentType();
+ internalConfig.safeToKillPackages = config.getSafeToKillPackages();
+ internalConfig.vendorPackagePrefixes = config.getVendorPackagePrefixes();
+ internalConfig.packageMetadata = new ArrayList<>();
+ for (Map.Entry<String, String> entry : config.getPackagesToAppCategoryTypes().entrySet()) {
+ if (entry.getKey().isEmpty()) {
+ continue;
+ }
+ PackageMetadata metadata = new PackageMetadata();
+ metadata.packageName = entry.getKey();
+ switch(entry.getValue()) {
+ case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
+ metadata.appCategoryType = ApplicationCategoryType.MAPS;
+ break;
+ case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
+ metadata.appCategoryType = ApplicationCategoryType.MEDIA;
+ break;
+ default:
+ continue;
+ }
+ internalConfig.packageMetadata.add(metadata);
+ }
+ internalConfig.resourceSpecificConfigurations = new ArrayList<>();
+ if ((resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0
+ && config.getIoOveruseConfiguration() != null) {
+ internalConfig.resourceSpecificConfigurations.add(
+ toResourceSpecificConfiguration(config.getComponentType(),
+ config.getIoOveruseConfiguration()));
+ }
+ return internalConfig;
+ }
+
+ private static ResourceSpecificConfiguration
+ toResourceSpecificConfiguration(int componentType, IoOveruseConfiguration config) {
+ android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig =
+ new android.automotive.watchdog.internal.IoOveruseConfiguration();
+ internalConfig.componentLevelThresholds = toPerStateIoOveruseThreshold(
+ toComponentTypeStr(componentType), config.getComponentLevelThresholds());
+ internalConfig.packageSpecificThresholds = toPerStateIoOveruseThresholds(
+ config.getPackageSpecificThresholds());
+ internalConfig.categorySpecificThresholds = toPerStateIoOveruseThresholds(
+ config.getAppCategorySpecificThresholds());
+ for (PerStateIoOveruseThreshold threshold : internalConfig.categorySpecificThresholds) {
+ switch(threshold.name) {
+ case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS:
+ threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS;
+ break;
+ case ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA:
+ threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA;
+ break;
+ default:
+ threshold.name = INTERNAL_APPLICATION_CATEGORY_TYPE_UNKNOWN;
+ }
+ }
+ internalConfig.systemWideThresholds = toInternalIoOveruseAlertThresholds(
+ config.getSystemWideThresholds());
+
+ ResourceSpecificConfiguration resourceSpecificConfig = new ResourceSpecificConfiguration();
+ resourceSpecificConfig.setIoOveruseConfiguration(internalConfig);
+ return resourceSpecificConfig;
+ }
+
+ @VisibleForTesting
+ static String toComponentTypeStr(int componentType) {
+ switch(componentType) {
+ case ComponentType.SYSTEM:
+ return "SYSTEM";
+ case ComponentType.VENDOR:
+ return "VENDOR";
+ case ComponentType.THIRD_PARTY:
+ return "THIRD_PARTY";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private static List<PerStateIoOveruseThreshold> toPerStateIoOveruseThresholds(
+ Map<String, PerStateBytes> thresholds) {
+ List<PerStateIoOveruseThreshold> internalThresholds = new ArrayList<>();
+ for (Map.Entry<String, PerStateBytes> entry : thresholds.entrySet()) {
+ if (!entry.getKey().isEmpty()) {
+ internalThresholds.add(toPerStateIoOveruseThreshold(entry.getKey(),
+ entry.getValue()));
+ }
+ }
+ return internalThresholds;
+ }
+
+ private static PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(String name,
+ PerStateBytes perStateBytes) {
+ PerStateIoOveruseThreshold threshold = new PerStateIoOveruseThreshold();
+ threshold.name = name;
+ threshold.perStateWriteBytes = new android.automotive.watchdog.PerStateBytes();
+ threshold.perStateWriteBytes.foregroundBytes = perStateBytes.getForegroundModeBytes();
+ threshold.perStateWriteBytes.backgroundBytes = perStateBytes.getBackgroundModeBytes();
+ threshold.perStateWriteBytes.garageModeBytes = perStateBytes.getGarageModeBytes();
+ return threshold;
+ }
+
+ private static List<android.automotive.watchdog.internal.IoOveruseAlertThreshold>
+ toInternalIoOveruseAlertThresholds(List<IoOveruseAlertThreshold> thresholds) {
+ List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds =
+ new ArrayList<>();
+ for (IoOveruseAlertThreshold threshold : thresholds) {
+ if (threshold.getDurationInSeconds() == 0
+ || threshold.getWrittenBytesPerSecond() == 0) {
+ continue;
+ }
+ android.automotive.watchdog.internal.IoOveruseAlertThreshold internalThreshold =
+ new android.automotive.watchdog.internal.IoOveruseAlertThreshold();
+ internalThreshold.durationInSeconds = threshold.getDurationInSeconds();
+ internalThreshold.writtenBytesPerSecond = threshold.getWrittenBytesPerSecond();
+ internalThresholds.add(internalThreshold);
+ }
+ return internalThresholds;
+ }
+
+ private static ResourceOveruseConfiguration toResourceOveruseConfiguration(
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration internalConfig,
+ @CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag) {
+ Map<String, String> packagesToAppCategoryTypes = new ArrayMap<>();
+ for (PackageMetadata metadata : internalConfig.packageMetadata) {
+ String categoryTypeStr;
+ switch (metadata.appCategoryType) {
+ case ApplicationCategoryType.MAPS:
+ categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS;
+ break;
+ case ApplicationCategoryType.MEDIA:
+ categoryTypeStr = ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA;
+ break;
+ default:
+ continue;
+ }
+ packagesToAppCategoryTypes.put(metadata.packageName, categoryTypeStr);
+ }
+ ResourceOveruseConfiguration.Builder configBuilder =
+ new ResourceOveruseConfiguration.Builder(
+ internalConfig.componentType,
+ internalConfig.safeToKillPackages,
+ internalConfig.vendorPackagePrefixes,
+ packagesToAppCategoryTypes);
+ for (ResourceSpecificConfiguration resourceSpecificConfig :
+ internalConfig.resourceSpecificConfigurations) {
+ if (resourceSpecificConfig.getTag()
+ == ResourceSpecificConfiguration.ioOveruseConfiguration
+ && (resourceOveruseFlag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
+ configBuilder.setIoOveruseConfiguration(toIoOveruseConfiguration(
+ resourceSpecificConfig.getIoOveruseConfiguration()));
+ }
+ }
+ return configBuilder.build();
+ }
+
+ private static IoOveruseConfiguration toIoOveruseConfiguration(
+ android.automotive.watchdog.internal.IoOveruseConfiguration internalConfig) {
+ PerStateBytes componentLevelThresholds =
+ toPerStateBytes(internalConfig.componentLevelThresholds.perStateWriteBytes);
+ Map<String, PerStateBytes> packageSpecificThresholds =
+ toPerStateBytesMap(internalConfig.packageSpecificThresholds);
+ Map<String, PerStateBytes> appCategorySpecificThresholds =
+ toPerStateBytesMap(internalConfig.categorySpecificThresholds);
+ replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS,
+ ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS);
+ replaceKey(appCategorySpecificThresholds, INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA,
+ ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA);
+ List<IoOveruseAlertThreshold> systemWideThresholds =
+ toIoOveruseAlertThresholds(internalConfig.systemWideThresholds);
+
+ IoOveruseConfiguration.Builder configBuilder = new IoOveruseConfiguration.Builder(
+ componentLevelThresholds, packageSpecificThresholds, appCategorySpecificThresholds,
+ systemWideThresholds);
+ return configBuilder.build();
+ }
+
+ private static Map<String, PerStateBytes> toPerStateBytesMap(
+ List<PerStateIoOveruseThreshold> thresholds) {
+ Map<String, PerStateBytes> thresholdsMap = new ArrayMap<>();
+ for (PerStateIoOveruseThreshold threshold : thresholds) {
+ thresholdsMap.put(threshold.name, toPerStateBytes(threshold.perStateWriteBytes));
+ }
+ return thresholdsMap;
+ }
+
+ private static List<IoOveruseAlertThreshold> toIoOveruseAlertThresholds(
+ List<android.automotive.watchdog.internal.IoOveruseAlertThreshold> internalThresholds) {
+ List<IoOveruseAlertThreshold> thresholds = new ArrayList<>();
+ for (android.automotive.watchdog.internal.IoOveruseAlertThreshold internalThreshold
+ : internalThresholds) {
+ thresholds.add(new IoOveruseAlertThreshold(internalThreshold.durationInSeconds,
+ internalThreshold.writtenBytesPerSecond));
+ }
+ return thresholds;
+ }
+
+ private static void replaceKey(Map<String, PerStateBytes> map, String oldKey, String newKey) {
+ PerStateBytes perStateBytes = map.get(oldKey);
+ if (perStateBytes != null) {
+ map.put(newKey, perStateBytes);
+ map.remove(oldKey);
+ }
+ }
+
+ private final class PackageResourceUsage {
public final String packageName;
public @UserIdInt final int userId;
public final PackageIoUsage ioUsage;
@@ -583,15 +1038,17 @@
private @KillableState int mKillableState;
+ /** Must be called only after acquiring {@link mLock} */
PackageResourceUsage(@UserIdInt int userId, String packageName) {
this.packageName = packageName;
this.userId = userId;
this.ioUsage = new PackageIoUsage();
this.oldEnabledState = -1;
- this.mKillableState = KILLABLE_STATE_YES;
+ this.mKillableState = mDefaultNotKillablePackages.contains(packageName)
+ ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
}
- public void update(android.automotive.watchdog.IoOveruseStats internalStats) {
+ public void updateLocked(android.automotive.watchdog.IoOveruseStats internalStats) {
if (!internalStats.killableOnOveruse) {
/*
* Killable value specified in the internal stats is provided by the native daemon.
@@ -600,20 +1057,28 @@
* vendor services and doesn't reflect the user choices. Thus if the internal stats
* specify the application is not killable, the application is not safe-to-kill.
*/
- this.mKillableState = KILLABLE_STATE_NEVER;
+ mKillableState = KILLABLE_STATE_NEVER;
+ } else if (mKillableState == KILLABLE_STATE_NEVER) {
+ /*
+ * This case happens when a previously unsafe to kill system/vendor package was
+ * recently marked as safe-to-kill so update the old state to the default value.
+ */
+ mKillableState = mDefaultNotKillablePackages.contains(packageName)
+ ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
}
ioUsage.update(internalStats);
}
- public ResourceOveruseStats getResourceOveruseStatsWithIo() {
- IoOveruseStats ioOveruseStats = null;
- if (ioUsage.hasUsage()) {
- ioOveruseStats = ioUsage.getStatsBuilder().setKillableOnOveruse(
- mKillableState != PackageKillableState.KILLABLE_STATE_NEVER).build();
- }
+ public ResourceOveruseStats.Builder getResourceOveruseStatsBuilder() {
+ return new ResourceOveruseStats.Builder(packageName, UserHandle.of(userId));
+ }
- return new ResourceOveruseStats.Builder(packageName, UserHandle.of(userId))
- .setIoOveruseStats(ioOveruseStats).build();
+ public IoOveruseStats getIoOveruseStats() {
+ if (!ioUsage.hasUsage()) {
+ return null;
+ }
+ return ioUsage.getStatsBuilder().setKillableOnOveruse(
+ mKillableState != KILLABLE_STATE_NEVER).build();
}
public @KillableState int getKillableState() {
@@ -621,12 +1086,30 @@
}
public boolean setKillableState(boolean isKillable) {
- if (mKillableState == PackageKillableState.KILLABLE_STATE_NEVER) {
+ if (mKillableState == KILLABLE_STATE_NEVER) {
return false;
}
mKillableState = isKillable ? KILLABLE_STATE_YES : KILLABLE_STATE_NO;
return true;
}
+
+ public int syncAndFetchKillableStateLocked(int myComponentType) {
+ /*
+ * The killable state goes out-of-sync:
+ * 1. When the on-device safe-to-kill list is recently updated and the user package
+ * didn't have any resource usage so the native daemon didn't update the killable state.
+ * 2. When a package has no resource usage and is initialized outside of processing the
+ * latest resource usage stats.
+ */
+ if (myComponentType != ComponentType.THIRD_PARTY
+ && !mSafeToKillPackages.contains(packageName)) {
+ mKillableState = KILLABLE_STATE_NEVER;
+ } else if (mKillableState == KILLABLE_STATE_NEVER) {
+ mKillableState = mDefaultNotKillablePackages.contains(packageName)
+ ? KILLABLE_STATE_NO : KILLABLE_STATE_YES;
+ }
+ return mKillableState;
+ }
}
private static final class PackageIoUsage {
@@ -697,7 +1180,7 @@
@Override
public void binderDied() {
- Slogf.w(TAG, "Resource overuse listener%s (pid: %d) died",
+ Slogf.w(CarWatchdogService.TAG, "Resource overuse listener%s (pid: %d) died",
isListenerForSystem ? " for system" : "", pid);
onResourceOveruseListenerDeath(uid, isListenerForSystem);
unlinkToDeath();
diff --git a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
index 59e76c7..2754755 100644
--- a/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogProcessHandler.java
@@ -37,7 +37,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.car.CarLog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.utils.Slogf;
@@ -47,11 +46,9 @@
* Handles clients' health status checking and reporting the statuses to the watchdog daemon.
*/
public final class WatchdogProcessHandler {
- private static final String TAG = CarLog.tagFor(CarWatchdogService.class);
private static final int[] ALL_TIMEOUTS =
{ TIMEOUT_CRITICAL, TIMEOUT_MODERATE, TIMEOUT_NORMAL };
- private final boolean mIsDebugEnabled;
private final ICarWatchdogServiceForSystem mWatchdogServiceForSystem;
private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
@@ -85,8 +82,7 @@
private final SparseBooleanArray mStoppedUser = new SparseBooleanArray();
public WatchdogProcessHandler(ICarWatchdogServiceForSystem serviceImpl,
- CarWatchdogDaemonHelper daemonHelper, boolean isDebugEnabled) {
- mIsDebugEnabled = isDebugEnabled;
+ CarWatchdogDaemonHelper daemonHelper) {
mWatchdogServiceForSystem = serviceImpl;
mCarWatchdogDaemonHelper = daemonHelper;
}
@@ -98,8 +94,8 @@
mPingedClientMap.put(timeout, new SparseArray<ClientInfo>());
mClientCheckInProgress.put(timeout, false);
}
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "WatchdogProcessHandler is initialized");
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "WatchdogProcessHandler is initialized");
}
}
@@ -136,14 +132,15 @@
synchronized (mLock) {
ArrayList<ClientInfo> clients = mClientMap.get(timeout);
if (clients == null) {
- Slogf.w(TAG, "Cannot register the client: invalid timeout");
+ Slogf.w(CarWatchdogService.TAG, "Cannot register the client: invalid timeout");
return;
}
IBinder binder = client.asBinder();
for (int i = 0; i < clients.size(); i++) {
ClientInfo clientInfo = clients.get(i);
if (binder == clientInfo.client.asBinder()) {
- Slogf.w(TAG, "Cannot register the client: the client(pid: %d) has been already "
+ Slogf.w(CarWatchdogService.TAG,
+ "Cannot register the client: the client(pid: %d) has been already "
+ "registered", clientInfo.pid);
return;
}
@@ -154,12 +151,13 @@
try {
clientInfo.linkToDeath();
} catch (RemoteException e) {
- Slogf.w(TAG, "Cannot register the client: linkToDeath to the client failed");
+ Slogf.w(CarWatchdogService.TAG,
+ "Cannot register the client: linkToDeath to the client failed");
return;
}
clients.add(clientInfo);
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "Client(pid: %d) is registered", pid);
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Client(pid: %d) is registered", pid);
}
}
}
@@ -177,14 +175,16 @@
}
clientInfo.unlinkToDeath();
clients.remove(i);
- if (mIsDebugEnabled) {
- Slogf.d(TAG, "Client(pid: %d) is unregistered", clientInfo.pid);
+ if (CarWatchdogService.DEBUG) {
+ Slogf.d(CarWatchdogService.TAG, "Client(pid: %d) is unregistered",
+ clientInfo.pid);
}
return;
}
}
}
- Slogf.w(TAG, "Cannot unregister the client: the client has not been registered before");
+ Slogf.w(CarWatchdogService.TAG,
+ "Cannot unregister the client: the client has not been registered before");
return;
}
@@ -297,8 +297,8 @@
try {
clientInfo.client.onCheckHealthStatus(clientInfo.sessionId, timeout);
} catch (RemoteException e) {
- Slogf.w(TAG, "Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid,
- e);
+ Slogf.w(CarWatchdogService.TAG,
+ "Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid, e);
synchronized (mLock) {
pingedClients.remove(clientInfo.sessionId);
}
@@ -348,7 +348,8 @@
try {
clientInfo.client.onPrepareProcessTermination();
} catch (RemoteException e) {
- Slogf.w(TAG, "Notifying onPrepareProcessTermination to client(pid: %d) failed: %s",
+ Slogf.w(CarWatchdogService.TAG,
+ "Notifying onPrepareProcessTermination to client(pid: %d) failed: %s",
clientInfo.pid, e);
}
}
@@ -357,7 +358,8 @@
mCarWatchdogDaemonHelper.tellCarWatchdogServiceAlive(
mWatchdogServiceForSystem, clientsNotResponding, sessionId);
} catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Cannot respond to car watchdog daemon (sessionId=%d): %s", sessionId, e);
+ Slogf.w(CarWatchdogService.TAG,
+ "Cannot respond to car watchdog daemon (sessionId=%d): %s", sessionId, e);
}
}
@@ -380,7 +382,7 @@
case TIMEOUT_NORMAL:
return "normal";
default:
- Slogf.w(TAG, "Unknown timeout value");
+ Slogf.w(CarWatchdogService.TAG, "Unknown timeout value");
return "unknown";
}
}
@@ -394,7 +396,7 @@
case TIMEOUT_NORMAL:
return 10000L;
default:
- Slogf.w(TAG, "Unknown timeout value");
+ Slogf.w(CarWatchdogService.TAG, "Unknown timeout value");
return 10000L;
}
}
@@ -416,7 +418,7 @@
@Override
public void binderDied() {
- Slogf.w(TAG, "Client(pid: %d) died", pid);
+ Slogf.w(CarWatchdogService.TAG, "Client(pid: %d) died", pid);
onClientDeath(client, timeout);
}
diff --git a/tests/CarEvsCameraPreviewApp/Android.bp b/tests/CarEvsCameraPreviewApp/Android.bp
index eb5f704..99f0505 100644
--- a/tests/CarEvsCameraPreviewApp/Android.bp
+++ b/tests/CarEvsCameraPreviewApp/Android.bp
@@ -13,6 +13,10 @@
// 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: "CarEvsCameraPreviewApp",
diff --git a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
index 59cdedc..d06620a 100644
--- a/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
+++ b/tests/CarEvsCameraPreviewApp/src/com/google/android/car/evs/jni/Android.bp
@@ -14,6 +14,10 @@
//
//
//#################################
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_library_shared {
name: "libcarevsglrenderer_jni",
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/bluetooth_devices.xml b/tests/EmbeddedKitchenSinkApp/res/layout/bluetooth_devices.xml
new file mode 100644
index 0000000..c856233
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/bluetooth_devices.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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:columnCount = "2">
+ <TextView
+ android:id="@+id/bluetooth_device"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <Button
+ android:id="@+id/bluetooth_pick_device"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bluetooth_pick_device"/>
+ <TableLayout
+ android:id="@+id/PairedDeviceTable"
+ android:layout_width="409dp"
+ android:layout_height="190dp"
+ tools:layout_editor_absoluteX="1dp"
+ tools:layout_editor_absoluteY="1dp"/>
+</GridLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index acbc2ad..01748a6 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -47,6 +47,7 @@
import com.google.android.car.kitchensink.assistant.CarAssistantFragment;
import com.google.android.car.kitchensink.audio.AudioTestFragment;
import com.google.android.car.kitchensink.audio.CarAudioInputTestFragment;
+import com.google.android.car.kitchensink.bluetooth.BluetoothDeviceFragment;
import com.google.android.car.kitchensink.bluetooth.BluetoothHeadsetFragment;
import com.google.android.car.kitchensink.bluetooth.MapMceTestFragment;
import com.google.android.car.kitchensink.carboard.KeyboardTestFragment;
@@ -173,6 +174,7 @@
new FragmentMenuEntry("assistant", CarAssistantFragment.class),
new FragmentMenuEntry("audio", AudioTestFragment.class),
new FragmentMenuEntry("Audio Input", CarAudioInputTestFragment.class),
+ new FragmentMenuEntry("BT device", BluetoothDeviceFragment.class),
new FragmentMenuEntry("BT headset", BluetoothHeadsetFragment.class),
new FragmentMenuEntry("BT messaging", MapMceTestFragment.class),
new FragmentMenuEntry("carapi", CarApiTestFragment.class),
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceFragment.java
new file mode 100644
index 0000000..c1de700
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceFragment.java
@@ -0,0 +1,162 @@
+/*
+ * 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.kitchensink.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothDevicePicker;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+public class BluetoothDeviceFragment extends Fragment {
+ private static final String TAG = "CAR.BLUETOOTH.KS";
+ BluetoothAdapter mBluetoothAdapter;
+ BluetoothDevice mPickedDevice;
+ Executor mExecutor;
+ BluetoothDeviceTypeChecker mDeviceTypeChecker;
+
+ TextView mPickedDeviceText;
+ Button mDevicePicker;
+ TableLayout mTableLayout;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.bluetooth_devices, container, false);
+ mDeviceTypeChecker = new BluetoothDeviceTypeChecker(getContext(), true);
+ mDevicePicker = v.findViewById(R.id.bluetooth_pick_device);
+ mTableLayout = v.findViewById(R.id.PairedDeviceTable);
+ mExecutor = new ThreadPerTaskExecutor();
+
+ // Pick a bluetooth device
+ mDevicePicker.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ launchDevicePicker();
+ }
+ });
+
+ return v;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ checkAllDevices();
+ }
+
+ void launchDevicePicker() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
+ getContext().registerReceiver(mPickerReceiver, filter);
+
+ Intent intent = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
+ intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ getContext().startActivity(intent);
+ }
+
+ void checkAllDevices() {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (bluetoothAdapter == null) {
+ Log.w(TAG, "Bluetooth Adapter not available");
+ return;
+ }
+ mTableLayout.removeAllViews();
+ Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();
+ Context context = getContext();
+ for (BluetoothDevice device : bondedDevices) {
+ TableRow row = new TableRow(context);
+ TextView deviceName = new TextView(context);
+ deviceName.setText(device.getName());
+ TextView deviceType = new TextView(context);
+ deviceType.setText(Boolean.toString(mDeviceTypeChecker.isIapDevice(device)));
+ row.addView(deviceName);
+ row.addView(deviceType);
+ mTableLayout.addView(row);
+ }
+ }
+
+ private void addDeviceToTable(BluetoothDevice device, String value) {
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ Context context = getContext();
+ TableRow row = new TableRow(context);
+ TextView deviceName = new TextView(context);
+ TextView deviceValue = new TextView(context);
+ deviceName.setText(device.getName());
+ deviceValue.setText(value);
+ row.addView(deviceName);
+ row.addView(deviceValue);
+ mTableLayout.addView(row);
+ }
+ });
+ }
+
+ private final BroadcastReceiver mPickerReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.v(TAG, "mPickerReceiver got " + action);
+
+ if (BluetoothDevicePicker.ACTION_DEVICE_SELECTED.equals(action)) {
+ final BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ Log.v(TAG, "mPickerReceiver got " + device);
+ if (device == null) {
+ Toast.makeText(getContext(), "No device selected", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ addDeviceToTable(device,
+ Boolean.toString(mDeviceTypeChecker.isIapDevice(device)));
+ Log.w(TAG, "Is iAP" + mDeviceTypeChecker.isIapDevice(device));
+ }
+ });
+ Log.w(TAG, "Dispatched");
+ getContext().unregisterReceiver(mPickerReceiver);
+ }
+ }
+ };
+
+ private class ThreadPerTaskExecutor implements Executor {
+ public void execute(Runnable r) {
+ new Thread(r).start();
+ }
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceTypeChecker.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceTypeChecker.java
new file mode 100644
index 0000000..1523634
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/bluetooth/BluetoothDeviceTypeChecker.java
@@ -0,0 +1,137 @@
+/*
+ * 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.kitchensink.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+public class BluetoothDeviceTypeChecker {
+ private static final ParcelUuid IAP_UUID =
+ ParcelUuid.fromString("00000000-deca-fade-deca-deafdecacafe");
+ private static final int MAX_SECONDS_TO_BLOCK = 10;
+ private static final String TAG = "BluetoothDeviceTypeChecker";
+
+ private final Context mContext;
+ private final boolean mAllowBlocking;
+ private final Object mLock = new Object();
+
+ CompletableFuture<ParcelUuid[]> mDeviceUUidsFuture;
+ BluetoothDevice mBluetoothDevice;
+
+ /**
+ * BluetoothDeviceTypeChecker
+ * Class designed to fetch and check UUID records for matches based on either cached or live
+ * records. Live records are fetched if allowBlocking is enabled and there is nothing in the
+ * cache. Paired devices should always have records in the cache if the BluetoothAdapter is on.
+ *
+ * @param context The context on which to receive updates if live records are necessary
+ * @param allowBlocking If cached SDP records are not available allow methods to block in a
+ * best effort of acquiring them.
+ */
+ public BluetoothDeviceTypeChecker(Context context, boolean allowBlocking) {
+ mContext = context;
+ if (mContext != null) {
+ mAllowBlocking = allowBlocking;
+ } else {
+ mAllowBlocking = false;
+ }
+ }
+
+ /**
+ * isIapDevice
+ * Check if device is indicating support for iAP
+ * @param device
+ * @return
+ */
+ public boolean isIapDevice(BluetoothDevice device) {
+ return deviceContainsUuid(device, IAP_UUID);
+ }
+
+ /**
+ * deviceContainsUuid
+ * Check if device contains a specific UUID record
+ * @param device to perform a lookup on
+ * @param uuid to check in the records
+ * @return
+ */
+ public boolean deviceContainsUuid(BluetoothDevice device, ParcelUuid uuid) {
+ if (device == null) return false;
+ if (uuid == null) return false;
+
+ synchronized (mLock) {
+ mBluetoothDevice = device;
+ ParcelUuid[] uuidsArray = device.getUuids();
+ if (mAllowBlocking && (uuidsArray == null || uuidsArray.length == 0)) {
+ uuidsArray = blockingFetchUuids(device);
+ }
+ if (uuidsArray == null || uuidsArray.length == 0) {
+ return false;
+ }
+ for (int i = 0; i < uuidsArray.length; i++) {
+ if (uuid.equals(uuidsArray[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /*
+ Perform a blocking fetch of the UUIDs on specified BluetoothDevice
+ */
+ private ParcelUuid[] blockingFetchUuids(BluetoothDevice device) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothDevice.ACTION_UUID);
+ mContext.registerReceiver(mUuidReceiver, filter);
+ mDeviceUUidsFuture = new CompletableFuture<>();
+ if (!device.fetchUuidsWithSdp()) {
+ Log.w(TAG, "fetching UUIDs failed.");
+ mContext.unregisterReceiver(mUuidReceiver);
+ return new ParcelUuid[0];
+ }
+ try {
+ return mDeviceUUidsFuture.get(MAX_SECONDS_TO_BLOCK, TimeUnit.SECONDS);
+ } catch (Exception e) {
+ mContext.unregisterReceiver(mUuidReceiver);
+ return new ParcelUuid[0];
+ }
+ }
+
+ /*
+ Broadcast receiver on which to receive updates to Bluetooth UUID records.
+ */
+ private BroadcastReceiver mUuidReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (mBluetoothDevice.equals(device)
+ && BluetoothDevice.ACTION_UUID.equals(intent.getAction())) {
+ mDeviceUUidsFuture.complete(device.getUuids());
+ mContext.unregisterReceiver(this);
+ }
+ }
+ };
+}
diff --git a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
index 2fb64d4..abafdf6 100644
--- a/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarPropertyManagerTest.java
@@ -112,6 +112,23 @@
| VehicleArea.GLOBAL;
private static final Integer[] FAKE_INT_ARRAY_VALUE = {1, 2};
+ private static final int INT_ARRAY_PROP_STATUS_ERROR =
+ 0x1104 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC
+ | VehicleArea.GLOBAL;
+
+ private static final int BOOLEAN_PROP_STATUS_ERROR =
+ 0x1105 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.BOOLEAN
+ | VehicleArea.GLOBAL;
+ private static final boolean FAKE_BOOLEAN_PROPERTY_VALUE = true;
+ private static final int FLOAT_PROP_STATUS_UNAVAILABLE =
+ 0x1106 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.FLOAT
+ | VehicleArea.GLOBAL;
+ private static final float FAKE_FLOAT_PROPERTY_VALUE = 3f;
+ private static final int INT_PROP_STATUS_UNAVAILABLE =
+ 0x1107 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32
+ | VehicleArea.GLOBAL;
+ private static final int FAKE_INT_PROPERTY_VALUE = 3;
+
// Vendor properties for testing exceptions.
private static final int PROP_CAUSE_STATUS_CODE_TRY_AGAIN =
0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL;
@@ -161,8 +178,10 @@
private void setUpTargetSdk() {
if (mTestName.getMethodName().endsWith("InQ")) {
getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.Q;
- } else if (mTestName.getMethodName().endsWith("InR")) {
+ } else if (mTestName.getMethodName().endsWith("AfterQ")) {
getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R;
+ } else if (mTestName.getMethodName().endsWith("AfterR")) {
+ getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S;
}
}
@@ -192,6 +211,10 @@
case CUSTOM_SEAT_INT_PROP_1:
case CUSTOM_SEAT_INT_PROP_2:
case CUSTOM_GLOBAL_INT_ARRAY_PROP:
+ case INT_ARRAY_PROP_STATUS_ERROR:
+ case BOOLEAN_PROP_STATUS_ERROR:
+ case INT_PROP_STATUS_UNAVAILABLE:
+ case FLOAT_PROP_STATUS_UNAVAILABLE:
case VehiclePropertyIds.INFO_VIN:
break;
default:
@@ -235,6 +258,64 @@
}
/**
+ * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with
+ * error status.
+ */
+ @Test
+ public void testGetIntArrayPropertyWithErrorStatusAfterR() {
+ Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+ .isGreaterThan(Build.VERSION_CODES.R);
+ mManager.setProperty(Integer[].class, INT_ARRAY_PROP_STATUS_ERROR,
+ VehicleArea.GLOBAL, FAKE_INT_ARRAY_VALUE);
+ assertThrows(CarInternalErrorException.class,
+ () -> mManager.getIntArrayProperty(INT_ARRAY_PROP_STATUS_ERROR,
+ VehicleArea.GLOBAL));
+ }
+
+ /**
+ * Test {@link CarPropertyManager#getIntProperty(int, int)} when vhal returns a value with
+ * unavailable status.
+ */
+ @Test
+ public void testGetIntPropertyWithUnavailableStatusAfterR() {
+ Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+ .isGreaterThan(Build.VERSION_CODES.R);
+ mManager.setProperty(Integer.class, INT_PROP_STATUS_UNAVAILABLE,
+ VehicleArea.GLOBAL, FAKE_INT_PROPERTY_VALUE);
+ assertThrows(PropertyNotAvailableException.class,
+ () -> mManager.getIntProperty(INT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL));
+
+ }
+
+ /**
+ * Test {@link CarPropertyManager#getBooleanProperty(int, int)} when vhal returns a value with
+ * error status.
+ */
+ @Test
+ public void testGetBooleanPropertyWithErrorStatusAfterR() {
+ Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+ .isGreaterThan(Build.VERSION_CODES.R);
+ mManager.setProperty(Boolean.class, BOOLEAN_PROP_STATUS_ERROR,
+ VehicleArea.GLOBAL, FAKE_BOOLEAN_PROPERTY_VALUE);
+ assertThrows(CarInternalErrorException.class,
+ () -> mManager.getBooleanProperty(BOOLEAN_PROP_STATUS_ERROR, VehicleArea.GLOBAL));
+ }
+
+ /**
+ * Test {@link CarPropertyManager#getFloatProperty(int, int)} when vhal returns a value with
+ * unavailable status.
+ */
+ @Test
+ public void testGetFloatPropertyWithUnavailableStatusAfterR() {
+ Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
+ .isGreaterThan(Build.VERSION_CODES.R);
+ mManager.setProperty(Float.class, FLOAT_PROP_STATUS_UNAVAILABLE,
+ VehicleArea.GLOBAL, FAKE_FLOAT_PROPERTY_VALUE);
+ assertThrows(PropertyNotAvailableException.class,
+ () -> mManager.getFloatProperty(FLOAT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL));
+ }
+
+ /**
* Test {@link CarPropertyManager#getProperty(Class, int, int)}
*/
@Test
@@ -373,9 +454,9 @@
}
@Test
- public void testSetterExceptionsInR() {
+ public void testSetterExceptionsAfterQ() {
Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
- .isEqualTo(Build.VERSION_CODES.R);
+ .isGreaterThan(Build.VERSION_CODES.Q);
assertThrows(PropertyAccessDeniedSecurityException.class,
()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
@@ -402,39 +483,74 @@
assertThrows(IllegalStateException.class,
()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(IllegalStateException.class,
+ ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(IllegalArgumentException.class,
()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(IllegalArgumentException.class,
+ ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(IllegalStateException.class,
()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
assertThrows(IllegalStateException.class,
+ ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
+ assertThrows(IllegalStateException.class,
()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(IllegalStateException.class,
+ ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
Truth.assertThat(mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)).isNull();
}
@Test
- public void testGetterExceptionsInR() {
+ public void testGetterExceptionsAfterQ() {
Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion)
- .isEqualTo(Build.VERSION_CODES.R);
+ .isAtLeast(Build.VERSION_CODES.R);
assertThrows(PropertyAccessDeniedSecurityException.class,
() -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(PropertyAccessDeniedSecurityException.class,
+ () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(IllegalArgumentException.class,
() -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(IllegalArgumentException.class,
+ () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(PropertyNotAvailableAndRetryException.class,
() -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(PropertyNotAvailableAndRetryException.class,
+ () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(PropertyNotAvailableException.class,
() -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(PropertyNotAvailableException.class,
+ () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+
assertThrows(CarInternalErrorException.class,
() -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
+ assertThrows(CarInternalErrorException.class,
+ () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL));
}
@Test
@@ -616,6 +732,11 @@
addProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_3, handler).setConfigArray(CONFIG_ARRAY_3);
addProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, handler);
+ addProperty(INT_ARRAY_PROP_STATUS_ERROR, handler);
+ addProperty(INT_PROP_STATUS_UNAVAILABLE, handler);
+ addProperty(FLOAT_PROP_STATUS_UNAVAILABLE, handler);
+ addProperty(BOOLEAN_PROP_STATUS_ERROR, handler);
+
VehiclePropValue tempValue = new VehiclePropValue();
tempValue.value.floatValues.add(INIT_TEMP_VALUE);
tempValue.prop = VehiclePropertyIds.HVAC_TEMPERATURE_SET;
@@ -640,7 +761,7 @@
@Override
public synchronized void onPropertySet(VehiclePropValue value) {
// Simulate HalClient.set() behavior.
- int statusCode = mapPropertyToStatusCode(value.prop);
+ int statusCode = mapPropertyToVhalStatusCode(value.prop);
if (statusCode == VehicleHalStatusCode.STATUS_INVALID_ARG) {
throw new IllegalArgumentException();
}
@@ -655,17 +776,23 @@
@Override
public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
// Simulate HalClient.get() behavior.
- int statusCode = mapPropertyToStatusCode(value.prop);
- if (statusCode == VehicleHalStatusCode.STATUS_INVALID_ARG) {
+ int vhalStatusCode = mapPropertyToVhalStatusCode(value.prop);
+ if (vhalStatusCode == VehicleHalStatusCode.STATUS_INVALID_ARG) {
throw new IllegalArgumentException();
}
- if (statusCode != VehicleHalStatusCode.STATUS_OK) {
- throw new ServiceSpecificException(statusCode);
+ if (vhalStatusCode != VehicleHalStatusCode.STATUS_OK) {
+ throw new ServiceSpecificException(vhalStatusCode);
}
+ int propertyStatus = mapPropertyToCarPropertyStatusCode(value.prop);
VehiclePropValue currentValue = mMap.get(value.prop);
- return currentValue != null ? currentValue : value;
+ if (currentValue == null) {
+ return value;
+ } else {
+ currentValue.status = propertyStatus;
+ }
+ return currentValue;
}
@Override
@@ -684,7 +811,7 @@
return VehiclePropertyIds.toString(propertyId) + " (" + propertyId + ")";
}
- private static int mapPropertyToStatusCode(int propId) {
+ private static int mapPropertyToVhalStatusCode(int propId) {
switch (propId) {
case PROP_CAUSE_STATUS_CODE_TRY_AGAIN:
return VehicleHalStatusCode.STATUS_TRY_AGAIN;
@@ -701,6 +828,19 @@
}
}
+ private static int mapPropertyToCarPropertyStatusCode(int propId) {
+ switch (propId) {
+ case INT_ARRAY_PROP_STATUS_ERROR:
+ case BOOLEAN_PROP_STATUS_ERROR:
+ return CarPropertyValue.STATUS_ERROR;
+ case INT_PROP_STATUS_UNAVAILABLE:
+ case FLOAT_PROP_STATUS_UNAVAILABLE:
+ return CarPropertyValue.STATUS_UNAVAILABLE;
+ default:
+ return CarPropertyValue.STATUS_AVAILABLE;
+ }
+ }
+
private static class TestErrorCallback implements CarPropertyManager.CarPropertyEventCallback {
private static final String CALLBACK_TAG = "ErrorEventTest";
diff --git a/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java b/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
index c0e20f2d..611efd4 100644
--- a/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/cluster/ClusterHomeManagerTest.java
@@ -68,8 +68,10 @@
private static final int UI_TYPE_2 = 2;
private static final byte[] UI_AVAILABILITY = new byte[] {(byte) 1, (byte) 0, (byte) 1};
- private static final int WIDTH = 800;
- private static final int HEIGHT = 600;
+ private static final int BOUNDS_LEFT = 0;
+ private static final int BOUNDS_TOP = 1;
+ private static final int BOUNDS_RIGHT = 800;
+ private static final int BOUNDS_BOTTOM = 601;
private static final int INSET_LEFT = 20;
private static final int INSET_TOP = 10;
private static final int INSET_RIGHT = 780;
@@ -189,13 +191,16 @@
@Test
public void testClusterState() throws InterruptedException {
getMockedVehicleHal().injectEvent(createDisplayStateEvent(
- DISPLAY_ON, WIDTH, HEIGHT, INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM));
+ DISPLAY_ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
+ INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM));
mCallbackReceived.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertThat(mState).isNotNull();
assertThat(mState.on).isEqualTo(true);
- assertThat(mState.width).isEqualTo(WIDTH);
- assertThat(mState.height).isEqualTo(HEIGHT);
+ assertThat(mState.bounds.left).isEqualTo(BOUNDS_LEFT);
+ assertThat(mState.bounds.top).isEqualTo(BOUNDS_TOP);
+ assertThat(mState.bounds.right).isEqualTo(BOUNDS_RIGHT);
+ assertThat(mState.bounds.bottom).isEqualTo(BOUNDS_BOTTOM);
assertThat(mState.insets.left).isEqualTo(INSET_LEFT);
assertThat(mState.insets.top).isEqualTo(INSET_TOP);
assertThat(mState.insets.right).isEqualTo(INSET_RIGHT);
@@ -208,8 +213,7 @@
assertThat(state2).isNotNull();
// The class generated from aidl doesn't have the proper equals() method yet.
assertThat(state2.on).isEqualTo(mState.on);
- assertThat(state2.width).isEqualTo(mState.width);
- assertThat(state2.height).isEqualTo(mState.height);
+ assertThat(state2.bounds).isEqualTo(mState.bounds);
assertThat(state2.insets).isEqualTo(mState.insets);
}
@@ -220,7 +224,7 @@
VehiclePropValue value = mPropertyHandler.peek(VehicleProperty.CLUSTER_REPORT_STATE);
assertThat(value.prop).isEqualTo(VehicleProperty.CLUSTER_REPORT_STATE);
- assertThat(value.value.int32Values.subList(7, 9)).containsExactly(UI_TYPE_1, UI_TYPE_2);
+ assertThat(value.value.int32Values.subList(9, 11)).containsExactly(UI_TYPE_1, UI_TYPE_2);
assertThat(value.value.bytes).containsExactly(
(Byte) UI_AVAILABILITY[0], (Byte) UI_AVAILABILITY[1], (Byte) UI_AVAILABILITY[2]);
}
@@ -334,17 +338,20 @@
return event;
}
- private static VehiclePropValue createDisplayStateEvent(int onOff, int width, int height,
- int left, int top, int right, int bottom) {
+ private static VehiclePropValue createDisplayStateEvent(int onOff,
+ int boundsLeft, int boundsTop, int boundsRight, int boundsBottom,
+ int insetsLeft, int insetsTop, int insetSRight, int insetSBottom) {
VehiclePropValue event = new VehiclePropValue();
event.prop = CLUSTER_DISPLAY_STATE;
event.value.int32Values.add(onOff);
- event.value.int32Values.add(width);
- event.value.int32Values.add(height);
- event.value.int32Values.add(left);
- event.value.int32Values.add(top);
- event.value.int32Values.add(right);
- event.value.int32Values.add(bottom);
+ event.value.int32Values.add(boundsLeft);
+ event.value.int32Values.add(boundsTop);
+ event.value.int32Values.add(boundsRight);
+ event.value.int32Values.add(boundsBottom);
+ event.value.int32Values.add(insetsLeft);
+ event.value.int32Values.add(insetsTop);
+ event.value.int32Values.add(insetSRight);
+ event.value.int32Values.add(insetSBottom);
return event;
}
}
diff --git a/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java
new file mode 100644
index 0000000..f83deee
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/JavaMockitoHelperTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.car.test.mocks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public final class JavaMockitoHelperTest {
+
+ private static final long TIMEOUT_MS = 1_000L;
+
+ @Test
+ public void testAwait_Semaphore() throws InterruptedException {
+ Semaphore semaphore = new Semaphore(1);
+
+ JavaMockitoHelper.await(semaphore, TIMEOUT_MS);
+
+ assertThat(semaphore.availablePermits()).isEqualTo(0);
+ }
+
+ @Test
+ public void testAwait_CountDownLatch() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ new Thread(() -> latch.countDown(), "testAwait_CountDownLatch").start();
+
+ JavaMockitoHelper.await(latch, TIMEOUT_MS);
+
+ assertThat(latch.getCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testSilentAwait_notCalled() {
+ CountDownLatch latch = new CountDownLatch(1);
+
+ assertThat(JavaMockitoHelper.silentAwait(latch, 5L)).isFalse();
+ assertThat(latch.getCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testSilentAwait_called() {
+ CountDownLatch latch = new CountDownLatch(1);
+ new Thread(() -> latch.countDown(), "testSilentAwait_called").start();
+
+ assertThat(JavaMockitoHelper.silentAwait(latch, TIMEOUT_MS)).isTrue();
+ assertThat(latch.getCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetResult() throws InterruptedException, ExecutionException, TimeoutException {
+ Future<String> future = mock(Future.class);
+ when(future.get(anyLong(), any())).thenReturn("done");
+
+ assertThat(JavaMockitoHelper.getResult(future)).isEqualTo("done");
+ }
+
+ @Test
+ public void testGetResult_withCustomTimeout()
+ throws InterruptedException, ExecutionException, TimeoutException {
+ Future<String> future = mock(Future.class);
+ when(future.get(anyLong(), any(TimeUnit.class))).thenReturn("done");
+
+ assertThat(JavaMockitoHelper.getResult(future, TIMEOUT_MS)).isEqualTo("done");
+ verify(future).get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+}
diff --git a/tests/carservice_unit_test/src/android/car/test/util/SyncAnswerTest.java b/tests/carservice_unit_test/src/android/car/test/mocks/SyncAnswerTest.java
similarity index 97%
rename from tests/carservice_unit_test/src/android/car/test/util/SyncAnswerTest.java
rename to tests/carservice_unit_test/src/android/car/test/mocks/SyncAnswerTest.java
index 2e26e7e..4847588 100644
--- a/tests/carservice_unit_test/src/android/car/test/util/SyncAnswerTest.java
+++ b/tests/carservice_unit_test/src/android/car/test/mocks/SyncAnswerTest.java
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package android.car.test.util;
+package android.car.test.mocks;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.car.test.mocks.SyncAnswer;
-
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
index d682969..92dfb9a 100644
--- a/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
+++ b/tests/carservice_unit_test/src/android/car/watchdoglib/CarWatchdogDaemonHelperTest.java
@@ -20,11 +20,15 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.automotive.watchdog.internal.ComponentType;
import android.automotive.watchdog.internal.ICarWatchdog;
import android.automotive.watchdog.internal.ICarWatchdogMonitor;
import android.automotive.watchdog.internal.ICarWatchdogServiceForSystem;
@@ -32,6 +36,7 @@
import android.automotive.watchdog.internal.PackageIoOveruseStats;
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
import android.automotive.watchdog.internal.PowerCycle;
+import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
import android.automotive.watchdog.internal.StateType;
import android.os.Binder;
import android.os.IBinder;
@@ -47,6 +52,7 @@
import org.mockito.quality.Strictness;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -154,6 +160,31 @@
}
@Test
+ public void testIndirectCall_updateResourceOveruseConfigurations() throws Exception {
+ ResourceOveruseConfiguration config = new ResourceOveruseConfiguration();
+ config.componentType = ComponentType.SYSTEM;
+ List<ResourceOveruseConfiguration> configs = new ArrayList<>(Collections.singleton(config));
+
+ mCarWatchdogDaemonHelper.updateResourceOveruseConfigurations(configs);
+
+ verify(mFakeCarWatchdog).updateResourceOveruseConfigurations(eq(configs));
+ }
+
+ @Test
+ public void testIndirectCall_getResourceOveruseConfigurations() throws Exception {
+ ResourceOveruseConfiguration config = new ResourceOveruseConfiguration();
+ config.componentType = ComponentType.SYSTEM;
+ List<ResourceOveruseConfiguration> expected =
+ new ArrayList<>(Collections.singleton(config));
+ when(mFakeCarWatchdog.getResourceOveruseConfigurations()).thenReturn(expected);
+
+ List<ResourceOveruseConfiguration> actual =
+ mCarWatchdogDaemonHelper.getResourceOveruseConfigurations();
+
+ assertThat(actual).isEqualTo(expected);
+ }
+
+ @Test
public void testIndirectCall_actionTakenOnResourceOveruse() throws Exception {
List<PackageResourceOveruseAction> actions = new ArrayList<>();
diff --git a/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java b/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
index da1eb72..ed37a9b 100644
--- a/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/admin/CarDevicePolicyServiceTest.java
@@ -26,6 +26,8 @@
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.user.UserCreationResult;
import android.car.user.UserRemovalResult;
+import android.car.user.UserStartResult;
+import android.car.user.UserStopResult;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
import android.os.UserManager;
@@ -44,11 +46,13 @@
private CarDevicePolicyService mService;
- private AndroidFuture<UserRemovalResult> mUserRemovalResult =
- new AndroidFuture<UserRemovalResult>();
+ private AndroidFuture<UserRemovalResult> mUserRemovalResult = new AndroidFuture<>();
- private AndroidFuture<UserCreationResult> mUserCreationResult =
- new AndroidFuture<UserCreationResult>();
+ private AndroidFuture<UserCreationResult> mUserCreationResult = new AndroidFuture<>();
+
+ private AndroidFuture<UserStartResult> mUserStartResult = new AndroidFuture<>();
+
+ private AndroidFuture<UserStopResult> mUserStopResult = new AndroidFuture<>();
@Before
public void setFixtures() {
@@ -104,4 +108,18 @@
verify(mCarUserService).createUser(eq("name"), eq(userType), eq(flags),
/* timeoutMs= */ anyInt(), eq(mUserCreationResult));
}
+
+ @Test
+ public void testStartUserInBackground() {
+ mService.startUserInBackground(42, mUserStartResult);
+
+ verify(mCarUserService).startUserInBackground(42, mUserStartResult);
+ }
+
+ @Test
+ public void testStopUser() {
+ mService.stopUser(42, mUserStopResult);
+
+ verify(mCarUserService).stopUser(42, mUserStopResult);
+ }
}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/ClusterHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/ClusterHalServiceTest.java
index 21d99a8..5b47294 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/ClusterHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/ClusterHalServiceTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verify;
import android.graphics.Insets;
+import android.graphics.Rect;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import com.android.car.hal.ClusterHalService.ClusterHalEventCallback;
@@ -55,8 +56,10 @@
private static final int UI_TYPE_2 = 2;
private static final byte[] UI_AVAILABILITY = new byte[] {(byte) 1, (byte) 1, (byte) 0};
- private static final int WIDTH = 800;
- private static final int HEIGHT = 600;
+ private static final int BOUNDS_LEFT = 0;
+ private static final int BOUNDS_TOP = 1;
+ private static final int BOUNDS_RIGHT = 800;
+ private static final int BOUNDS_BOTTOM = 601;
private static final int INSET_LEFT = 20;
private static final int INSET_TOP = 10;
private static final int INSET_RIGHT = 780;
@@ -71,8 +74,7 @@
int mUiType = NOT_ASSIGNED;
int mOnOff = NOT_ASSIGNED;
- int mWidth = NOT_ASSIGNED;
- int mHeight = NOT_ASSIGNED;
+ Rect mBounds = null;
Insets mInsets = null;
private final ClusterHalEventCallback mHalEventListener = new ClusterHalEventCallback() {
@@ -80,10 +82,9 @@
mUiType = uiType;
}
- public void onDisplayState(int onOff, int width, int height, Insets insets) {
+ public void onDisplayState(int onOff, Rect bounds, Insets insets) {
mOnOff = onOff;
- mWidth = width;
- mHeight = height;
+ mBounds = bounds;
mInsets = insets;
}
};
@@ -162,17 +163,20 @@
return event;
}
- private static VehiclePropValue createDisplayStateEvent(int onOff, int width, int height,
- int left, int top, int right, int bottom) {
+ private static VehiclePropValue createDisplayStateEvent(int onOff,
+ int boundsLeft, int boundsTop, int boundsRight, int boundsBottom,
+ int insetsLeft, int insetsTop, int insetSRight, int insetSBottom) {
VehiclePropValue event = new VehiclePropValue();
event.prop = CLUSTER_DISPLAY_STATE;
event.value.int32Values.add(onOff);
- event.value.int32Values.add(width);
- event.value.int32Values.add(height);
- event.value.int32Values.add(left);
- event.value.int32Values.add(top);
- event.value.int32Values.add(right);
- event.value.int32Values.add(bottom);
+ event.value.int32Values.add(boundsLeft);
+ event.value.int32Values.add(boundsTop);
+ event.value.int32Values.add(boundsRight);
+ event.value.int32Values.add(boundsBottom);
+ event.value.int32Values.add(insetsLeft);
+ event.value.int32Values.add(insetsTop);
+ event.value.int32Values.add(insetSRight);
+ event.value.int32Values.add(insetSBottom);
return event;
}
@@ -207,12 +211,14 @@
@Test
public void testOnDisplayState() {
mClusterHalService.onHalEvents(Arrays.asList(
- createDisplayStateEvent(ON, WIDTH, HEIGHT,
+ createDisplayStateEvent(ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM)));
assertThat(mOnOff).isEqualTo(ON);
- assertThat(mWidth).isEqualTo(WIDTH);
- assertThat(mHeight).isEqualTo(HEIGHT);
+ assertThat(mBounds.left).isEqualTo(BOUNDS_LEFT);
+ assertThat(mBounds.top).isEqualTo(BOUNDS_TOP);
+ assertThat(mBounds.right).isEqualTo(BOUNDS_RIGHT);
+ assertThat(mBounds.bottom).isEqualTo(BOUNDS_BOTTOM);
assertThat(mInsets.left).isEqualTo(INSET_LEFT);
assertThat(mInsets.top).isEqualTo(INSET_TOP);
assertThat(mInsets.right).isEqualTo(INSET_RIGHT);
@@ -220,14 +226,13 @@
}
@Test
- public void testOnDisplayState_DontAcceptPartialDontCare_Height() {
+ public void testOnDisplayState_DontAcceptPartialDontCare_Bounds() {
mClusterHalService.onHalEvents(Arrays.asList(
- createDisplayStateEvent(ON, WIDTH, DONT_CARE,
+ createDisplayStateEvent(ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, DONT_CARE,
INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM)));
assertThat(mOnOff).isEqualTo(ON);
- assertThat(mWidth).isEqualTo(NOT_ASSIGNED);
- assertThat(mHeight).isEqualTo(NOT_ASSIGNED);
+ assertThat(mBounds).isNull();
assertThat(mInsets.left).isEqualTo(INSET_LEFT);
assertThat(mInsets.top).isEqualTo(INSET_TOP);
assertThat(mInsets.right).isEqualTo(INSET_RIGHT);
@@ -237,12 +242,14 @@
@Test
public void testOnDisplayState_DontAcceptPartialDontCare_Inset() {
mClusterHalService.onHalEvents(Arrays.asList(
- createDisplayStateEvent(ON, WIDTH, HEIGHT,
+ createDisplayStateEvent(ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
INSET_LEFT, INSET_TOP, INSET_RIGHT, DONT_CARE)));
assertThat(mOnOff).isEqualTo(ON);
- assertThat(mWidth).isEqualTo(WIDTH);
- assertThat(mHeight).isEqualTo(HEIGHT);
+ assertThat(mBounds.left).isEqualTo(BOUNDS_LEFT);
+ assertThat(mBounds.top).isEqualTo(BOUNDS_TOP);
+ assertThat(mBounds.right).isEqualTo(BOUNDS_RIGHT);
+ assertThat(mBounds.bottom).isEqualTo(BOUNDS_BOTTOM);
assertThat(mInsets).isNull();
}
@@ -251,12 +258,11 @@
mClusterHalService.setCallback(null);
mClusterHalService.onHalEvents(Arrays.asList(
- createDisplayStateEvent(ON, WIDTH, HEIGHT,
+ createDisplayStateEvent(ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM)));
assertThat(mOnOff).isEqualTo(NOT_ASSIGNED);
- assertThat(mWidth).isEqualTo(NOT_ASSIGNED);
- assertThat(mHeight).isEqualTo(NOT_ASSIGNED);
+ assertThat(mBounds).isNull();
assertThat(mInsets).isNull();
}
@@ -265,25 +271,26 @@
mClusterHalService.takeProperties(Arrays.asList());
mClusterHalService.onHalEvents(Arrays.asList(
- createDisplayStateEvent(ON, WIDTH, HEIGHT,
+ createDisplayStateEvent(ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM)));
assertThat(mOnOff).isEqualTo(NOT_ASSIGNED);
- assertThat(mWidth).isEqualTo(NOT_ASSIGNED);
- assertThat(mHeight).isEqualTo(NOT_ASSIGNED);
+ assertThat(mBounds).isNull();
assertThat(mInsets).isNull();
}
@Test
public void testReportState() {
- mClusterHalService.reportState(ON, WIDTH, HEIGHT,
+ mClusterHalService.reportState(
+ ON, new Rect(BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM),
Insets.of(INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM),
UI_TYPE_1, UI_TYPE_2, UI_AVAILABILITY);
verify(mVehicleHal).set(mPropCaptor.capture());
VehiclePropValue prop = mPropCaptor.getValue();
assertThat(prop.prop).isEqualTo(CLUSTER_REPORT_STATE);
- assertThat(prop.value.int32Values).containsExactly(ON, WIDTH, HEIGHT,
+ assertThat(prop.value.int32Values).containsExactly(
+ ON, BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM,
INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM, UI_TYPE_1, UI_TYPE_2);
assertThat(prop.value.bytes).containsExactly(
(Byte) UI_AVAILABILITY[0], (Byte) UI_AVAILABILITY[1], (Byte) UI_AVAILABILITY[2]);
@@ -293,7 +300,8 @@
public void testReportState_noProperties() {
mClusterHalService.takeProperties(Arrays.asList());
- mClusterHalService.reportState(ON, WIDTH, HEIGHT,
+ mClusterHalService.reportState(
+ ON, new Rect(BOUNDS_LEFT, BOUNDS_TOP, BOUNDS_RIGHT, BOUNDS_BOTTOM),
Insets.of(INSET_LEFT, INSET_TOP, INSET_RIGHT, INSET_BOTTOM),
UI_TYPE_1, UI_TYPE_2, UI_AVAILABILITY);
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
index adafb57..4620c81 100644
--- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -72,6 +72,8 @@
import android.car.user.UserCreationResult;
import android.car.user.UserIdentificationAssociationResponse;
import android.car.user.UserRemovalResult;
+import android.car.user.UserStartResult;
+import android.car.user.UserStopResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.HalCallback;
import android.car.userlib.HalCallback.HalCallbackStatus;
@@ -528,9 +530,9 @@
UserInfo user2Info = new UserInfo(user2, "user2", NO_USER_INFO_FLAGS);
UserInfo user3Info = new UserInfo(user3, "user3", NO_USER_INFO_FLAGS);
- doReturn(user1Info).when(mMockedUserManager).getUserInfo(user1);
- doReturn(user2Info).when(mMockedUserManager).getUserInfo(user2);
- doReturn(user3Info).when(mMockedUserManager).getUserInfo(user3);
+ when(mMockedUserManager.getUserInfo(user1)).thenReturn(user1Info);
+ when(mMockedUserManager.getUserInfo(user2)).thenReturn(user2Info);
+ when(mMockedUserManager.getUserInfo(user3)).thenReturn(user3Info);
mockGetCurrentUser(user1);
sendUserUnlockedEvent(UserHandle.USER_SYSTEM);
@@ -540,40 +542,108 @@
sendUserUnlockedEvent(user1);
mockGetCurrentUser(user3);
sendUserUnlockedEvent(user3);
+ mockStopUserWithDelayedLocking(user3, ActivityManager.USER_OP_IS_CURRENT);
- assertEquals(new Integer[]{user3, user2},
- mCarUserService.getBackgroundUsersToRestart().toArray());
+ assertThat(mCarUserService.getBackgroundUsersToRestart()).containsExactly(user2, user3);
- doReturn(true).when(mMockedIActivityManager).startUserInBackground(user2);
- doReturn(true).when(mMockedIActivityManager).unlockUser(user2,
- null, null, null);
- assertEquals(new Integer[]{user2},
- mCarUserService.startAllBackgroundUsers().toArray());
+ when(mMockedIActivityManager.startUserInBackground(user2)).thenReturn(true);
+ when(mMockedIActivityManager.unlockUser(user2, null, null, null)).thenReturn(true);
+ assertThat(mCarUserService.startAllBackgroundUsers()).containsExactly(user2);
sendUserUnlockedEvent(user2);
- assertEquals(new Integer[]{user3, user2},
- mCarUserService.getBackgroundUsersToRestart().toArray());
+ assertThat(mCarUserService.getBackgroundUsersToRestart()).containsExactly(user2, user3);
- doReturn(ActivityManager.USER_OP_SUCCESS).when(mMockedIActivityManager).stopUser(user2,
- true, null);
+ when(mMockedIActivityManager.stopUser(user2, true, null))
+ .thenReturn(ActivityManager.USER_OP_SUCCESS);
// should not stop the current fg user
- assertFalse(mCarUserService.stopBackgroundUser(user3));
- assertTrue(mCarUserService.stopBackgroundUser(user2));
- assertEquals(new Integer[]{user3, user2},
- mCarUserService.getBackgroundUsersToRestart().toArray());
- assertEquals(new Integer[]{user3, user2},
- mCarUserService.getBackgroundUsersToRestart().toArray());
+ assertThat(mCarUserService.stopBackgroundUser(user3)).isFalse();
+ assertThat(mCarUserService.stopBackgroundUser(user2)).isTrue();
+ assertThat(mCarUserService.getBackgroundUsersToRestart()).containsExactly(user2, user3);
+ assertThat(mCarUserService.getBackgroundUsersToRestart()).containsExactly(user2, user3);
}
@Test
- public void testStopBackgroundUserForSystemUser() {
- assertFalse(mCarUserService.stopBackgroundUser(UserHandle.USER_SYSTEM));
+ public void testStopUser_success() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user101", NO_USER_INFO_FLAGS);
+ mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_SUCCESS);
+
+ AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+ mCarUserService.stopUser(userId, userStopResult);
+
+ assertThat(getResult(userStopResult).getStatus())
+ .isEqualTo(UserStopResult.STATUS_SUCCESSFUL);
+ assertThat(getResult(userStopResult).isSuccess()).isTrue();
}
@Test
- public void testStopBackgroundUserForFgUser() throws RemoteException {
- int user1 = 101;
- mockGetCurrentUser(user1);
- assertFalse(mCarUserService.stopBackgroundUser(UserHandle.USER_SYSTEM));
+ public void testStopUser_fail() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user101", NO_USER_INFO_FLAGS);
+ mockStopUserWithDelayedLockingThrowsRemoteException(userId);
+
+ AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+ mCarUserService.stopUser(userId, userStopResult);
+
+ assertThat(getResult(userStopResult).getStatus())
+ .isEqualTo(UserStopResult.STATUS_ANDROID_FAILURE);
+ assertThat(getResult(userStopResult).isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testStopUser_userDoesNotExist() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user101", NO_USER_INFO_FLAGS);
+ mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_UNKNOWN_USER);
+
+ AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+ mCarUserService.stopUser(userId, userStopResult);
+
+ assertThat(getResult(userStopResult).getStatus())
+ .isEqualTo(UserStopResult.STATUS_USER_DOES_NOT_EXIST);
+ assertThat(getResult(userStopResult).isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testStopUser_systemUser() throws Exception {
+ mockStopUserWithDelayedLocking(
+ UserHandle.USER_SYSTEM, ActivityManager.USER_OP_ERROR_IS_SYSTEM);
+
+ AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+ mCarUserService.stopUser(UserHandle.USER_SYSTEM, userStopResult);
+
+ assertThat(getResult(userStopResult).getStatus())
+ .isEqualTo(UserStopResult.STATUS_FAILURE_SYSTEM_USER);
+ assertThat(getResult(userStopResult).isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testStopUser_currentUser() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user101", NO_USER_INFO_FLAGS);
+ mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
+
+ AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
+ mCarUserService.stopUser(userId, userStopResult);
+
+ assertThat(getResult(userStopResult).getStatus())
+ .isEqualTo(UserStopResult.STATUS_FAILURE_CURRENT_USER);
+ assertThat(getResult(userStopResult).isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testStopBackgroundUserForSystemUser() throws Exception {
+ mockStopUserWithDelayedLocking(
+ UserHandle.USER_SYSTEM, ActivityManager.USER_OP_ERROR_IS_SYSTEM);
+
+ assertThat(mCarUserService.stopBackgroundUser(UserHandle.USER_SYSTEM)).isFalse();
+ }
+
+ @Test
+ public void testStopBackgroundUserForFgUser() throws Exception {
+ int userId = 101;
+ mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
+
+ assertThat(mCarUserService.stopBackgroundUser(userId)).isFalse();
}
@Test
@@ -1775,6 +1845,69 @@
}
@Test
+ public void testStartUserInBackground_success() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user1", NO_USER_INFO_FLAGS);
+ mockCurrentUser(mRegularUser);
+ mockUmGetUserInfo(mMockedUserManager, userInfo);
+ mockAmStartUserInBackground(userId, true);
+
+ AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
+ mCarUserService.startUserInBackground(userId, userStartResult);
+
+ assertThat(getResult(userStartResult).getStatus())
+ .isEqualTo(UserStartResult.STATUS_SUCCESSFUL);
+ assertThat(getResult(userStartResult).isSuccess()).isTrue();
+ }
+
+ @Test
+ public void testStartUserInBackground_fail() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user1", NO_USER_INFO_FLAGS);
+ mockCurrentUser(mRegularUser);
+ mockUmGetUserInfo(mMockedUserManager, userInfo);
+ mockAmStartUserInBackground(userId, false);
+
+ AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
+ mCarUserService.startUserInBackground(userId, userStartResult);
+
+ assertThat(getResult(userStartResult).getStatus())
+ .isEqualTo(UserStartResult.STATUS_ANDROID_FAILURE);
+ assertThat(getResult(userStartResult).isSuccess()).isFalse();
+ }
+
+ @Test
+ public void testStartUserInBackground_currentUser() throws Exception {
+ int userId = 101;
+ UserInfo userInfo = new UserInfo(userId, "user1", NO_USER_INFO_FLAGS);
+ mockGetCurrentUser(userId);
+ mockUmGetUserInfo(mMockedUserManager, userInfo);
+ mockAmStartUserInBackground(userId, true);
+
+ AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
+ mCarUserService.startUserInBackground(userId, userStartResult);
+
+ assertThat(getResult(userStartResult).getStatus())
+ .isEqualTo(UserStartResult.STATUS_SUCCESSFUL_USER_IS_CURRENT_USER);
+ assertThat(getResult(userStartResult).isSuccess()).isTrue();
+ }
+
+ @Test
+ public void testStartUserInBackground_userDoesNotExist() throws Exception {
+ int userId = 101;
+ mockCurrentUser(mRegularUser);
+ when(mMockedUserManager.getUserInfo(userId)).thenReturn(null);
+ mockAmStartUserInBackground(userId, true);
+
+ AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
+ mCarUserService.startUserInBackground(userId, userStartResult);
+
+ assertThat(getResult(userStartResult).getStatus())
+ .isEqualTo(UserStartResult.STATUS_USER_DOES_NOT_EXIST);
+ assertThat(getResult(userStartResult).isSuccess()).isFalse();
+ }
+
+ @Test
public void testIsHalSupported() throws Exception {
when(mUserHal.isSupported()).thenReturn(true);
assertThat(mCarUserService.isUserHalSupported()).isTrue();
@@ -2286,6 +2419,11 @@
mockGetCurrentUser(user.id);
}
+ private void mockAmStartUserInBackground(@UserIdInt int userId, boolean result)
+ throws Exception {
+ when(mMockedIActivityManager.startUserInBackground(userId)).thenReturn(result);
+ }
+
private void mockAmSwitchUser(@NonNull UserInfo user, boolean result) throws Exception {
when(mMockedIActivityManager.switchUser(user.id)).thenReturn(result);
}
@@ -2318,6 +2456,18 @@
/* listener= */ null);
}
+ private void mockStopUserWithDelayedLocking(@UserIdInt int userId, int result)
+ throws Exception {
+ when(mMockedIActivityManager.stopUserWithDelayedLocking(userId, true, null))
+ .thenReturn(result);
+ }
+
+ private void mockStopUserWithDelayedLockingThrowsRemoteException(@UserIdInt int userId)
+ throws Exception {
+ when(mMockedIActivityManager.stopUserWithDelayedLocking(userId, true, null))
+ .thenThrow(new RemoteException());
+ }
+
private void mockHalGetInitialInfo(@UserIdInt int currentUserId,
@NonNull InitialUserInfoResponse response) {
UsersInfo usersInfo = newUsersInfo(currentUserId);
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 fa4c30f..cdb3452 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
@@ -18,6 +18,7 @@
import static android.automotive.watchdog.internal.ResourceOveruseActionType.KILLED;
import static android.automotive.watchdog.internal.ResourceOveruseActionType.NOT_KILLED;
+import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetAliveUsers;
import static android.car.test.mocks.AndroidMockitoHelper.mockUmGetAllUsers;
import static android.car.watchdog.CarWatchdogManager.TIMEOUT_CRITICAL;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
@@ -51,13 +52,21 @@
import android.automotive.watchdog.internal.PackageIdentifier;
import android.automotive.watchdog.internal.PackageInfo;
import android.automotive.watchdog.internal.PackageIoOveruseStats;
+import android.automotive.watchdog.internal.PackageMetadata;
import android.automotive.watchdog.internal.PackageResourceOveruseAction;
+import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
+import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
import android.automotive.watchdog.internal.UidType;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.watchdog.CarWatchdogManager;
import android.car.watchdog.ICarWatchdogServiceCallback;
import android.car.watchdog.IResourceOveruseListener;
+import android.car.watchdog.IoOveruseAlertThreshold;
+import android.car.watchdog.IoOveruseConfiguration;
import android.car.watchdog.IoOveruseStats;
+import android.car.watchdog.PackageKillableState;
+import android.car.watchdog.PerStateBytes;
+import android.car.watchdog.ResourceOveruseConfiguration;
import android.car.watchdog.ResourceOveruseStats;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -66,13 +75,16 @@
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
+
+import com.android.internal.util.function.TriConsumer;
import com.google.common.truth.Correspondence;
@@ -89,6 +101,8 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* <p>This class contains unit tests for the {@link CarWatchdogService}.
@@ -102,9 +116,9 @@
@Mock private Context mMockContext;
@Mock private PackageManager mMockPackageManager;
- @Mock private UserManager mUserManager;
- @Mock private IBinder mBinder;
- @Mock private ICarWatchdog mCarWatchdogDaemon;
+ @Mock private UserManager mMockUserManager;
+ @Mock private IBinder mMockBinder;
+ @Mock private ICarWatchdog mMockCarWatchdogDaemon;
private CarWatchdogService mCarWatchdogService;
private ICarWatchdogServiceForSystem mWatchdogServiceForSystemImpl;
@@ -135,7 +149,7 @@
@Test
public void testCarWatchdogServiceHealthCheck() throws Exception {
mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
- verify(mCarWatchdogDaemon,
+ verify(mMockCarWatchdogDaemon,
timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
eq(mWatchdogServiceForSystemImpl), any(int[].class), eq(123456));
}
@@ -178,6 +192,204 @@
}
@Test
+ public void testGetResourceOveruseStats() throws Exception {
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
+ injectUidToPackageNameMapping(packageNamesByUid);
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>(
+ Collections.singletonList(
+ constructPackageIoOveruseStats(
+ Binder.getCallingUid(), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */false,
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)))
+ );
+ mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+
+ ResourceOveruseStats expectedStats =
+ constructResourceOveruseStats(packageNamesByUid.keyAt(0),
+ packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats);
+
+ ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
+
+ assertWithMessage("Expected: " + expectedStats.toString() + "\nActual: "
+ + actualStats.toString())
+ .that(ResourceOveruseStatsSubject.isEquals(actualStats, expectedStats)).isTrue();
+ }
+
+ @Test
+ public void testFailsGetResourceOveruseStatsWithInvalidArgs() throws Exception {
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseStats(/* resourceOveruseFlag= */0,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* maxStatsPeriod= */0));
+ }
+
+ @Test
+ public void testGetAllResourceOveruseStatsWithNoMinimum() throws Exception {
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(1103456, "third_party_package");
+ packageNamesByUid.put(1201278, "vendor_package.critical");
+ injectUidToPackageNameMapping(packageNamesByUid);
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>(Arrays.asList(
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */false,
+ /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
+ /* writtenBytes= */constructPerStateBytes(5000, 6000, 9000),
+ /* totalOveruses= */2))));
+ mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+
+ List<ResourceOveruseStats> expectedStats = new ArrayList<>(Arrays.asList(
+ constructResourceOveruseStats(packageNamesByUid.keyAt(0),
+ packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats),
+ constructResourceOveruseStats(packageNamesByUid.keyAt(1),
+ packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats))
+ );
+
+ List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */0,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
+
+ ResourceOveruseStatsSubject.assertThat(actualStats)
+ .containsExactlyElementsIn(expectedStats);
+ }
+
+ @Test
+ public void testFailsGetAllResourceOveruseStatsWithInvalidArgs() throws Exception {
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getAllResourceOveruseStats(0, /* minimumStatsFlag= */0,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getAllResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB
+ | CarWatchdogManager.FLAG_MINIMUM_STATS_IO_100_MB,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getAllResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */1 << 5,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getAllResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */0,
+ /* maxStatsPeriod= */0));
+ }
+
+ @Test
+ public void testGetAllResourceOveruseStatsWithMinimum() throws Exception {
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(1103456, "third_party_package");
+ packageNamesByUid.put(1201278, "vendor_package.critical");
+ injectUidToPackageNameMapping(packageNamesByUid);
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>(Arrays.asList(
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */false,
+ /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
+ /* writtenBytes= */constructPerStateBytes(7000000, 6000, 9000),
+ /* totalOveruses= */2))));
+ mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+
+ List<ResourceOveruseStats> expectedStats = new ArrayList<>(Arrays.asList(
+ constructResourceOveruseStats(packageNamesByUid.keyAt(1),
+ packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats))
+ );
+
+ List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.FLAG_MINIMUM_STATS_IO_1_MB,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
+
+ ResourceOveruseStatsSubject.assertThat(actualStats)
+ .containsExactlyElementsIn(expectedStats);
+ }
+
+ @Test
+ public void testGetResourceOveruseStatsForUserPackage() throws Exception {
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(1103456, "third_party_package");
+ packageNamesByUid.put(1201278, "vendor_package.critical");
+ injectUidToPackageNameMapping(packageNamesByUid);
+
+ List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>(Arrays.asList(
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
+ constructPackageIoOveruseStats(packageNamesByUid.keyAt(1), /* shouldNotify= */false,
+ constructInternalIoOveruseStats(/* killableOnOveruse= */false,
+ /* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
+ /* writtenBytes= */constructPerStateBytes(500, 600, 900),
+ /* totalOveruses= */2))));
+ mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+
+ ResourceOveruseStats expectedStats =
+ constructResourceOveruseStats(packageNamesByUid.keyAt(1),
+ packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats);
+
+ ResourceOveruseStats actualStats =
+ mCarWatchdogService.getResourceOveruseStatsForUserPackage(
+ "vendor_package.critical", new UserHandle(12),
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY);
+
+ assertWithMessage("Expected: " + expectedStats.toString() + "\nActual: "
+ + actualStats.toString())
+ .that(ResourceOveruseStatsSubject.isEquals(actualStats, expectedStats)).isTrue();
+ }
+
+ @Test
+ public void testFailsGetResourceOveruseStatsForUserPackageWithInvalidArgs() throws Exception {
+ assertThrows(NullPointerException.class,
+ () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage(
+ /* packageName= */null, new UserHandle(10),
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(NullPointerException.class,
+ () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
+ /* userHandle= */null, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
+ UserHandle.ALL, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
+ new UserHandle(10), /* resourceOveruseFlag= */0,
+ CarWatchdogManager.STATS_PERIOD_CURRENT_DAY));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseStatsForUserPackage("some.package",
+ new UserHandle(10), CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ /* maxStatsPeriod= */0));
+ }
+
+ @Test
public void testAddResourceOveruseListenerThrowsWithInvalidFlag() throws Exception {
IResourceOveruseListener mockListener = createMockResourceOveruseListener();
assertThrows(IllegalArgumentException.class, () -> {
@@ -203,8 +415,9 @@
Collections.singletonList(constructPackageIoOveruseStats(
callingUid, /* shouldNotify= */true,
constructInternalIoOveruseStats(/* killableOnOveruse= */true,
- constructPerStateBytes(20, 20, 20),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2))));
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2))));
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
@@ -246,8 +459,9 @@
Collections.singletonList(constructPackageIoOveruseStats(
callingUid, /* shouldNotify= */true,
constructInternalIoOveruseStats(/* killableOnOveruse= */true,
- constructPerStateBytes(20, 20, 20),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2))));
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2))));
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
@@ -264,6 +478,308 @@
}
@Test
+ public void testSetKillablePackageAsUserWithPackageStats() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(1103456, "third_party_package");
+ packageNamesByUid.put(1101278, "vendor_package.critical");
+ injectIoOveruseStatsForPackages(packageNamesByUid,
+ new ArraySet<>(Collections.singletonList("third_party_package")));
+
+ UserHandle userHandle = new UserHandle(11);
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+ /* isKillable= */ true);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ userHandle, /* isKillable= */ true));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+ /* isKillable= */ false);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ userHandle, /* isKillable= */ false));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testSetKillablePackageAsUserWithNoPackageStats() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+
+ UserHandle userHandle = new UserHandle(11);
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+ /* isKillable= */ true);
+ mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ userHandle, /* isKillable= */ true);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", userHandle,
+ /* isKillable= */ false);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ userHandle, /* isKillable= */ false));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(userHandle)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testSetKillablePackageAsUserForAllUsersWithPackageStats() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+
+ SparseArray<String> packageNamesByUid = new SparseArray<>();
+ packageNamesByUid.put(1103456, "third_party_package");
+ packageNamesByUid.put(1101278, "vendor_package.critical");
+ injectIoOveruseStatsForPackages(packageNamesByUid,
+ new ArraySet<>(Collections.singletonList("third_party_package")));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
+ /* isKillable= */ true);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ UserHandle.ALL, /* isKillable= */ true));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER),
+ new PackageKillableState("third_party_package", 12,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 12,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
+ /* isKillable= */ false);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ UserHandle.ALL, /* isKillable= */ false));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER),
+ new PackageKillableState("third_party_package", 12,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 12,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testSetKillablePackageAsUserForAllUsersWithNoPackageStats() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
+ /* isKillable= */ true);
+ mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ UserHandle.ALL, /* isKillable= */ true);
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER),
+ new PackageKillableState("third_party_package", 12,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 12,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+
+ mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
+ /* isKillable= */ false);
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setKillablePackageAsUser("vendor_package.critical",
+ UserHandle.ALL, /* isKillable= */ false));
+
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER),
+ new PackageKillableState("third_party_package", 12,
+ PackageKillableState.KILLABLE_STATE_NO),
+ new PackageKillableState("vendor_package.critical", 12,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testGetPackageKillableStatesAsUser() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(new UserHandle(11)))
+ .containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testGetPackageKillableStatesAsUserForAllUsers() throws Exception {
+ mockUmGetAliveUsers(mMockUserManager, 11, 12);
+ injectPackageInfos(new ArrayList<>(Arrays.asList("third_party_package",
+ "vendor_package.critical")));
+ PackageKillableStateSubject.assertThat(
+ mCarWatchdogService.getPackageKillableStatesAsUser(UserHandle.ALL)).containsExactly(
+ new PackageKillableState("third_party_package", 11,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 11,
+ PackageKillableState.KILLABLE_STATE_NEVER),
+ new PackageKillableState("third_party_package", 12,
+ PackageKillableState.KILLABLE_STATE_YES),
+ new PackageKillableState("vendor_package.critical", 12,
+ PackageKillableState.KILLABLE_STATE_NEVER));
+ }
+
+ @Test
+ public void testSetResourceOveruseConfigurations() throws Exception {
+ List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>(Arrays.asList(
+ sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+ sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build()).build(),
+ sampleResourceOveruseConfigurationBuilder(ComponentType.VENDOR,
+ sampleIoOveruseConfigurationBuilder(ComponentType.VENDOR).build()).build(),
+ sampleResourceOveruseConfigurationBuilder(ComponentType.THIRD_PARTY,
+ sampleIoOveruseConfigurationBuilder(ComponentType.THIRD_PARTY).build())
+ .build()));
+
+ mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
+
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
+ actualConfigs = captureOnSetResourceOveruseConfigurations();
+
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
+ expectedConfigs = new ArrayList<>(Arrays.asList(
+ sampleInternalResourceOveruseConfiguration(ComponentType.SYSTEM,
+ sampleInternalIoOveruseConfiguration(ComponentType.SYSTEM)),
+ sampleInternalResourceOveruseConfiguration(ComponentType.VENDOR,
+ sampleInternalIoOveruseConfiguration(ComponentType.VENDOR)),
+ sampleInternalResourceOveruseConfiguration(ComponentType.THIRD_PARTY,
+ sampleInternalIoOveruseConfiguration(ComponentType.THIRD_PARTY))));
+
+ InternalResourceOveruseConfigurationSubject.assertThat(actualConfigs)
+ .containsExactlyElementsIn(expectedConfigs);
+ }
+
+ @Test
+ public void testFailsSetResourceOveruseConfigurationsOnInvalidArgs() throws Exception {
+ assertThrows(NullPointerException.class,
+ () -> mCarWatchdogService.setResourceOveruseConfigurations(null,
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setResourceOveruseConfigurations(new ArrayList<>(),
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+
+ List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>(
+ Collections.singletonList(
+ sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+ sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build())
+ .build()));
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+ 0));
+ }
+
+ @Test
+ public void testFailsSetResourceOveruseConfigurationsOnDuplicateComponents() throws Exception {
+ ResourceOveruseConfiguration config =
+ sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+ sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build()).build();
+ List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>(Arrays.asList(
+ config, config));
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+ }
+
+ @Test
+ public void testFailsSetResourceOveruseConfigurationsOnNullIoOveruseConfiguration()
+ throws Exception {
+ List<ResourceOveruseConfiguration> resourceOveruseConfigs = new ArrayList<>(
+ Collections.singletonList(
+ sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+ null).build()));
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.setResourceOveruseConfigurations(resourceOveruseConfigs,
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO));
+ }
+
+ @Test
+ public void testGetResourceOveruseConfigurations() throws Exception {
+ List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
+ internalResourceOveruseConfigs = new ArrayList<>(Arrays.asList(
+ sampleInternalResourceOveruseConfiguration(ComponentType.SYSTEM,
+ sampleInternalIoOveruseConfiguration(ComponentType.SYSTEM)),
+ sampleInternalResourceOveruseConfiguration(ComponentType.VENDOR,
+ sampleInternalIoOveruseConfiguration(ComponentType.VENDOR)),
+ sampleInternalResourceOveruseConfiguration(ComponentType.THIRD_PARTY,
+ sampleInternalIoOveruseConfiguration(ComponentType.THIRD_PARTY))));
+ doReturn(internalResourceOveruseConfigs).when(mMockCarWatchdogDaemon)
+ .getResourceOveruseConfigurations();
+
+ List<ResourceOveruseConfiguration> actualConfigs =
+ mCarWatchdogService.getResourceOveruseConfigurations(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);
+
+ List<ResourceOveruseConfiguration> expectedConfigs = new ArrayList<>(Arrays.asList(
+ sampleResourceOveruseConfigurationBuilder(ComponentType.SYSTEM,
+ sampleIoOveruseConfigurationBuilder(ComponentType.SYSTEM).build()).build(),
+ sampleResourceOveruseConfigurationBuilder(ComponentType.VENDOR,
+ sampleIoOveruseConfigurationBuilder(ComponentType.VENDOR).build()).build(),
+ sampleResourceOveruseConfigurationBuilder(ComponentType.THIRD_PARTY,
+ sampleIoOveruseConfigurationBuilder(ComponentType.THIRD_PARTY).build())
+ .build()));
+
+ ResourceOveruseConfigurationSubject.assertThat(actualConfigs)
+ .containsExactlyElementsIn(expectedConfigs);
+ }
+
+ @Test
+ public void testFailsGetResourceOveruseConfigurationsOnInvalidArgs() throws Exception {
+ assertThrows(IllegalArgumentException.class,
+ () -> mCarWatchdogService.getResourceOveruseConfigurations(0));
+ }
+
+ @Test
public void testLatestIoOveruseStats() throws Exception {
int criticalSysPkgUid = Binder.getCallingUid();
int nonCriticalSysPkgUid = getUid(1056);
@@ -275,12 +791,6 @@
packageNamesByUid.put(nonCriticalSysPkgUid, "non_critical.system.package");
packageNamesByUid.put(nonCriticalVndrPkgUid, "non_critical.vendor.package");
packageNamesByUid.put(thirdPartyPkgUid, "third_party.package");
-
- SparseBooleanArray killableOnOveruseByUid = new SparseBooleanArray();
- killableOnOveruseByUid.put(criticalSysPkgUid, false);
- killableOnOveruseByUid.put(nonCriticalSysPkgUid, true);
- killableOnOveruseByUid.put(nonCriticalVndrPkgUid, true);
- killableOnOveruseByUid.put(thirdPartyPkgUid, true);
injectUidToPackageNameMapping(packageNamesByUid);
IResourceOveruseListener mockSystemListener = createMockResourceOveruseListener();
@@ -298,28 +808,28 @@
List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>(Arrays.asList(
/* Overuse occurred but cannot be killed/disabled. */
constructPackageIoOveruseStats(criticalSysPkgUid, /* shouldNotify= */true,
- constructInternalIoOveruseStats(
- killableOnOveruseByUid.get(criticalSysPkgUid),
- constructPerStateBytes(0, 0, 0),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2)),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */false,
+ /* remainingWriteBytes= */constructPerStateBytes(0, 0, 0),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
/* No overuse occurred but should be notified. */
constructPackageIoOveruseStats(nonCriticalSysPkgUid, /* shouldNotify= */true,
- constructInternalIoOveruseStats(
- killableOnOveruseByUid.get(nonCriticalSysPkgUid),
- constructPerStateBytes(20, 30, 40),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2)),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(20, 30, 40),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
/* Neither overuse occurred nor be notified. */
constructPackageIoOveruseStats(nonCriticalVndrPkgUid, /* shouldNotify= */false,
- constructInternalIoOveruseStats(
- killableOnOveruseByUid.get(nonCriticalVndrPkgUid),
- constructPerStateBytes(200, 300, 400),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2)),
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(200, 300, 400),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)),
/* Overuse occurred and can be killed/disabled. */
constructPackageIoOveruseStats(thirdPartyPkgUid, /* shouldNotify= */true,
- constructInternalIoOveruseStats(
- killableOnOveruseByUid.get(thirdPartyPkgUid),
- constructPerStateBytes(0, 0, 0),
- constructPerStateBytes(100, 200, 300), /* totalOveruses= */2))));
+ constructInternalIoOveruseStats(/* killableOnOveruse= */true,
+ /* remainingWriteBytes= */constructPerStateBytes(0, 0, 0),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2))));
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
@@ -327,19 +837,16 @@
expectedStats.add(constructResourceOveruseStats(criticalSysPkgUid,
packageNamesByUid.get(criticalSysPkgUid),
- killableOnOveruseByUid.get(criticalSysPkgUid),
packageIoOveruseStats.get(0).ioOveruseStats));
verifyOnOveruseCalled(expectedStats, mockListener);
expectedStats.add(constructResourceOveruseStats(nonCriticalSysPkgUid,
packageNamesByUid.get(nonCriticalSysPkgUid),
- killableOnOveruseByUid.get(nonCriticalSysPkgUid),
packageIoOveruseStats.get(1).ioOveruseStats));
expectedStats.add(constructResourceOveruseStats(thirdPartyPkgUid,
packageNamesByUid.get(thirdPartyPkgUid),
- killableOnOveruseByUid.get(thirdPartyPkgUid),
packageIoOveruseStats.get(3).ioOveruseStats));
verifyOnOveruseCalled(expectedStats, mockSystemListener);
@@ -499,19 +1006,19 @@
}
private void mockWatchdogDaemon() {
- doReturn(mBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
- when(mBinder.queryLocalInterface(anyString())).thenReturn(mCarWatchdogDaemon);
+ doReturn(mMockBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
+ when(mMockBinder.queryLocalInterface(anyString())).thenReturn(mMockCarWatchdogDaemon);
}
private void setupUsers() {
- when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
- mockUmGetAllUsers(mUserManager, new UserInfo[0]);
+ when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+ mockUmGetAllUsers(mMockUserManager, new UserInfo[0]);
}
private ICarWatchdogServiceForSystem registerCarWatchdogService() throws Exception {
ArgumentCaptor<ICarWatchdogServiceForSystem> watchdogServiceForSystemImplCaptor =
ArgumentCaptor.forClass(ICarWatchdogServiceForSystem.class);
- verify(mCarWatchdogDaemon).registerCarWatchdogService(
+ verify(mMockCarWatchdogDaemon).registerCarWatchdogService(
watchdogServiceForSystemImplCaptor.capture());
return watchdogServiceForSystemImplCaptor.getValue();
}
@@ -520,15 +1027,24 @@
mCarWatchdogService.registerClient(client, TIMEOUT_CRITICAL);
mWatchdogServiceForSystemImpl.checkIfAlive(123456, TIMEOUT_CRITICAL);
ArgumentCaptor<int[]> notRespondingClients = ArgumentCaptor.forClass(int[].class);
- verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
+ verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
eq(mWatchdogServiceForSystemImpl), notRespondingClients.capture(), eq(123456));
assertThat(notRespondingClients.getValue().length).isEqualTo(0);
mWatchdogServiceForSystemImpl.checkIfAlive(987654, TIMEOUT_CRITICAL);
- verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
+ verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).tellCarWatchdogServiceAlive(
eq(mWatchdogServiceForSystemImpl), notRespondingClients.capture(), eq(987654));
assertThat(notRespondingClients.getValue().length).isEqualTo(badClientCount);
}
+ private List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>
+ captureOnSetResourceOveruseConfigurations() throws Exception {
+ ArgumentCaptor<List<android.automotive.watchdog.internal.ResourceOveruseConfiguration>>
+ resourceOveruseConfigurationsCaptor = ArgumentCaptor.forClass(List.class);
+ verify(mMockCarWatchdogDaemon).updateResourceOveruseConfigurations(
+ resourceOveruseConfigurationsCaptor.capture());
+ return resourceOveruseConfigurationsCaptor.getValue();
+ }
+
private void injectUidToPackageNameMapping(SparseArray<String> packageNamesByUid) {
doAnswer(args -> {
int[] uids = args.getArgument(0);
@@ -540,6 +1056,49 @@
}).when(mMockPackageManager).getNamesForUids(any());
}
+ private void injectIoOveruseStatsForPackages(SparseArray<String> packageNamesByUid,
+ Set<String> killablePackages) throws RemoteException {
+ injectUidToPackageNameMapping(packageNamesByUid);
+ List<PackageIoOveruseStats> packageIoOveruseStats = new ArrayList<>();
+ for (int i = 0; i < packageNamesByUid.size(); ++i) {
+ String packageName = packageNamesByUid.valueAt(i);
+ int uid = packageNamesByUid.keyAt(i);
+ packageIoOveruseStats.add(constructPackageIoOveruseStats(uid,
+ false,
+ constructInternalIoOveruseStats(killablePackages.contains(packageName),
+ /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
+ /* writtenBytes= */constructPerStateBytes(100, 200, 300),
+ /* totalOveruses= */2)));
+ }
+ mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+ }
+
+ private void injectPackageInfos(List<String> packageNames) {
+ List<android.content.pm.PackageInfo> packageInfos = new ArrayList<>();
+ TriConsumer<String, Integer, Integer> addPackageInfo =
+ (packageName, flags, privateFlags) -> {
+ android.content.pm.PackageInfo packageInfo =
+ new android.content.pm.PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.flags = flags;
+ packageInfo.applicationInfo.privateFlags = privateFlags;
+ packageInfos.add(packageInfo);
+ };
+ for (String packageName : packageNames) {
+ if (packageName.startsWith("system")) {
+ addPackageInfo.accept(packageName, ApplicationInfo.FLAG_SYSTEM, 0);
+ } else if (packageName.startsWith("vendor")) {
+ addPackageInfo.accept(packageName, ApplicationInfo.FLAG_SYSTEM,
+ ApplicationInfo.PRIVATE_FLAG_OEM);
+ } else {
+ addPackageInfo.accept(packageName, 0, 0);
+ }
+ }
+ doReturn(packageInfos).when(mMockPackageManager).getInstalledPackagesAsUser(
+ eq(0), anyInt());
+ }
+
private void mockApplicationEnabledSettingAccessors(IPackageManager pm) throws Exception {
doReturn(COMPONENT_ENABLED_STATE_ENABLED).when(pm)
.getApplicationEnabledSetting(anyString(), eq(UserHandle.myUserId()));
@@ -553,7 +1112,7 @@
ArgumentCaptor<List<PackageResourceOveruseAction>> resourceOveruseActionsCaptor =
ArgumentCaptor.forClass((Class) List.class);
- verify(mCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).actionTakenOnResourceOveruse(
+ verify(mMockCarWatchdogDaemon, timeout(MAX_WAIT_TIME_MS)).actionTakenOnResourceOveruse(
resourceOveruseActionsCaptor.capture());
List<PackageResourceOveruseAction> actual = resourceOveruseActionsCaptor.getValue();
@@ -586,6 +1145,118 @@
return UserHandle.getUid(UserHandle.myUserId(), appId);
}
+ private static ResourceOveruseConfiguration.Builder sampleResourceOveruseConfigurationBuilder(
+ int componentType, IoOveruseConfiguration ioOveruseConfig) {
+ String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType);
+ List<String> safeToKill = new ArrayList<>(Arrays.asList(
+ prefix + "_package.A", prefix + "_pkg.B"));
+ List<String> vendorPrefixes = new ArrayList<>(Arrays.asList(
+ prefix + "_package", prefix + "_pkg"));
+ Map<String, String> pkgToAppCategory = new ArrayMap<>();
+ pkgToAppCategory.put(prefix + "_package.A", "android.car.watchdog.app.category.MEDIA");
+ ResourceOveruseConfiguration.Builder configBuilder =
+ new ResourceOveruseConfiguration.Builder(componentType, safeToKill,
+ vendorPrefixes, pkgToAppCategory);
+ configBuilder.setIoOveruseConfiguration(ioOveruseConfig);
+ return configBuilder;
+ }
+
+ private static IoOveruseConfiguration.Builder sampleIoOveruseConfigurationBuilder(
+ int componentType) {
+ String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType);
+ PerStateBytes componentLevelThresholds = new PerStateBytes(
+ /* foregroundModeBytes= */10, /* backgroundModeBytes= */20,
+ /* garageModeBytes= */30);
+ Map<String, PerStateBytes> packageSpecificThresholds = new ArrayMap<>();
+ packageSpecificThresholds.put(prefix + "_package.A", new PerStateBytes(
+ /* foregroundModeBytes= */40, /* backgroundModeBytes= */50,
+ /* garageModeBytes= */60));
+
+ Map<String, PerStateBytes> appCategorySpecificThresholds = new ArrayMap<>();
+ appCategorySpecificThresholds.put(
+ ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MEDIA,
+ new PerStateBytes(/* foregroundModeBytes= */100, /* backgroundModeBytes= */200,
+ /* garageModeBytes= */300));
+ appCategorySpecificThresholds.put(
+ ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS,
+ new PerStateBytes(/* foregroundModeBytes= */1100, /* backgroundModeBytes= */2200,
+ /* garageModeBytes= */3300));
+
+ List<IoOveruseAlertThreshold> systemWideThresholds = new ArrayList<>(
+ Collections.singletonList(new IoOveruseAlertThreshold(/* durationInSeconds= */10,
+ /* writtenBytesPerSecond= */200)));
+
+ return new IoOveruseConfiguration.Builder(componentLevelThresholds,
+ packageSpecificThresholds, appCategorySpecificThresholds, systemWideThresholds);
+ }
+
+ private static android.automotive.watchdog.internal.ResourceOveruseConfiguration
+ sampleInternalResourceOveruseConfiguration(int componentType,
+ android.automotive.watchdog.internal.IoOveruseConfiguration ioOveruseConfig) {
+ String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType);
+ android.automotive.watchdog.internal.ResourceOveruseConfiguration config =
+ new android.automotive.watchdog.internal.ResourceOveruseConfiguration();
+ config.componentType = componentType;
+ config.safeToKillPackages = new ArrayList<>(Arrays.asList(
+ prefix + "_package.A", prefix + "_pkg.B"));
+ config.vendorPackagePrefixes = new ArrayList<>(Arrays.asList(
+ prefix + "_package", prefix + "_pkg"));
+
+ PackageMetadata metadata = new PackageMetadata();
+ metadata.packageName = prefix + "_package.A";
+ metadata.appCategoryType = ApplicationCategoryType.MEDIA;
+ config.packageMetadata = new ArrayList<>(Collections.singletonList(metadata));
+
+ ResourceSpecificConfiguration resourceSpecificConfig = new ResourceSpecificConfiguration();
+ resourceSpecificConfig.setIoOveruseConfiguration(ioOveruseConfig);
+ config.resourceSpecificConfigurations = new ArrayList<>(
+ Collections.singletonList(resourceSpecificConfig));
+
+ return config;
+ }
+
+ private static android.automotive.watchdog.internal.IoOveruseConfiguration
+ sampleInternalIoOveruseConfiguration(int componentType) {
+ String prefix = WatchdogPerfHandler.toComponentTypeStr(componentType);
+ android.automotive.watchdog.internal.IoOveruseConfiguration config =
+ new android.automotive.watchdog.internal.IoOveruseConfiguration();
+ config.componentLevelThresholds = constructPerStateIoOveruseThreshold(prefix,
+ /* fgBytes= */10, /* bgBytes= */20, /* gmBytes= */30);
+ config.packageSpecificThresholds = new ArrayList<>(Collections.singletonList(
+ constructPerStateIoOveruseThreshold(prefix + "_package.A", /* fgBytes= */40,
+ /* bgBytes= */50, /* gmBytes= */60)));
+ config.categorySpecificThresholds = new ArrayList<>(Arrays.asList(
+ constructPerStateIoOveruseThreshold(
+ WatchdogPerfHandler.INTERNAL_APPLICATION_CATEGORY_TYPE_MEDIA,
+ /* fgBytes= */100, /* bgBytes= */200, /* gmBytes= */300),
+ constructPerStateIoOveruseThreshold(
+ WatchdogPerfHandler.INTERNAL_APPLICATION_CATEGORY_TYPE_MAPS,
+ /* fgBytes= */1100, /* bgBytes= */2200, /* gmBytes= */3300)));
+ config.systemWideThresholds = new ArrayList<>(Collections.singletonList(
+ constructInternalIoOveruseAlertThreshold(/* duration= */10, /* writeBPS= */200)));
+ return config;
+ }
+
+ private static PerStateIoOveruseThreshold constructPerStateIoOveruseThreshold(String name,
+ long fgBytes, long bgBytes, long gmBytes) {
+ PerStateIoOveruseThreshold threshold = new PerStateIoOveruseThreshold();
+ threshold.name = name;
+ threshold.perStateWriteBytes = new android.automotive.watchdog.PerStateBytes();
+ threshold.perStateWriteBytes.foregroundBytes = fgBytes;
+ threshold.perStateWriteBytes.backgroundBytes = bgBytes;
+ threshold.perStateWriteBytes.garageModeBytes = gmBytes;
+ return threshold;
+ }
+
+ private static android.automotive.watchdog.internal.IoOveruseAlertThreshold
+ constructInternalIoOveruseAlertThreshold(long duration, long writeBPS) {
+ android.automotive.watchdog.internal.IoOveruseAlertThreshold threshold =
+ new android.automotive.watchdog.internal.IoOveruseAlertThreshold();
+ threshold.durationInSeconds = duration;
+ threshold.writtenBytesPerSecond = writeBPS;
+ return threshold;
+ }
+
private static PackageIoOveruseStats constructPackageIoOveruseStats(int uid,
boolean shouldNotify, android.automotive.watchdog.IoOveruseStats ioOveruseStats) {
PackageIoOveruseStats stats = new PackageIoOveruseStats();
@@ -596,11 +1267,10 @@
}
private static ResourceOveruseStats constructResourceOveruseStats(int uid, String packageName,
- boolean killableOnOveruse,
android.automotive.watchdog.IoOveruseStats internalIoOveruseStats) {
IoOveruseStats ioOveruseStats =
WatchdogPerfHandler.toIoOveruseStatsBuilder(internalIoOveruseStats)
- .setKillableOnOveruse(killableOnOveruse).build();
+ .setKillableOnOveruse(internalIoOveruseStats.killableOnOveruse).build();
return new ResourceOveruseStats.Builder(packageName, UserHandle.getUserHandleForUid(uid))
.setIoOveruseStats(ioOveruseStats).build();
@@ -629,7 +1299,7 @@
return perStateBytes;
}
- public static PackageResourceOveruseAction constructPackageResourceOveruseAction(
+ private static PackageResourceOveruseAction constructPackageResourceOveruseAction(
String packageName, int uid, int[] resourceTypes, int resourceOveruseActionType) {
PackageResourceOveruseAction action = new PackageResourceOveruseAction();
action.packageIdentifier = new PackageIdentifier();
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/InternalIoOveruseConfigurationSubject.java b/tests/carservice_unit_test/src/com/android/car/watchdog/InternalIoOveruseConfigurationSubject.java
new file mode 100644
index 0000000..47ad645
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/InternalIoOveruseConfigurationSubject.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import android.annotation.Nullable;
+import android.automotive.watchdog.PerStateBytes;
+import android.automotive.watchdog.internal.IoOveruseAlertThreshold;
+import android.automotive.watchdog.internal.IoOveruseConfiguration;
+import android.automotive.watchdog.internal.PerStateIoOveruseThreshold;
+
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public final class InternalIoOveruseConfigurationSubject extends Subject {
+ // Boiler-plate Subject.Factory for InternalIoOveruseConfigurationSubject
+ private static final Subject.Factory<
+ com.android.car.watchdog.InternalIoOveruseConfigurationSubject,
+ Iterable<IoOveruseConfiguration>> Io_OVERUSE_CONFIG_SUBJECT_FACTORY =
+ com.android.car.watchdog.InternalIoOveruseConfigurationSubject::new;
+
+ private final Iterable<IoOveruseConfiguration> mActual;
+
+ // User-defined entry point
+ public static InternalIoOveruseConfigurationSubject assertThat(
+ @Nullable Iterable<IoOveruseConfiguration> stats) {
+ return assertAbout(Io_OVERUSE_CONFIG_SUBJECT_FACTORY).that(stats);
+ }
+
+ public static Subject.Factory<InternalIoOveruseConfigurationSubject,
+ Iterable<IoOveruseConfiguration>> resourceOveruseStats() {
+ return Io_OVERUSE_CONFIG_SUBJECT_FACTORY;
+ }
+
+ public void containsExactly(IoOveruseConfiguration... stats) {
+ containsExactlyElementsIn(Arrays.asList(stats));
+ }
+
+ public void containsExactlyElementsIn(Iterable<IoOveruseConfiguration> expected) {
+ Truth.assertWithMessage("Expected: " + expected.toString() + "\nActual: "
+ + mActual.toString()).that(mActual)
+ .comparingElementsUsing(Correspondence.from(
+ InternalIoOveruseConfigurationSubject::isEquals, "is equal to"))
+ .containsExactlyElementsIn(expected);
+ }
+
+ public static boolean isEquals(IoOveruseConfiguration actual,
+ IoOveruseConfiguration expected) {
+ if (actual == null || expected == null) {
+ return (actual == null) && (expected == null);
+ }
+ return actual.componentLevelThresholds.name == expected.componentLevelThresholds.name
+ && isPerStateBytesEquals(actual.componentLevelThresholds.perStateWriteBytes,
+ expected.componentLevelThresholds.perStateWriteBytes)
+ && isPerStateThresholdEquals(actual.packageSpecificThresholds,
+ expected.packageSpecificThresholds)
+ && isPerStateThresholdEquals(actual.categorySpecificThresholds,
+ expected.categorySpecificThresholds)
+ && isAlertThresholdEquals(actual.systemWideThresholds,
+ expected.systemWideThresholds);
+ }
+
+ public static StringBuilder toStringBuilder(StringBuilder builder,
+ IoOveruseConfiguration config) {
+ builder.append("{Component-level thresholds: ")
+ .append(toString(config.componentLevelThresholds))
+ .append(", Package specific thresholds: [")
+ .append(config.packageSpecificThresholds.stream()
+ .map(InternalIoOveruseConfigurationSubject::toString)
+ .collect(Collectors.joining(", ")))
+ .append("], Category specific thresholds: [")
+ .append(config.categorySpecificThresholds.stream()
+ .map(InternalIoOveruseConfigurationSubject::toString)
+ .collect(Collectors.joining(", ")))
+ .append("], System wide thresholds: [")
+ .append(config.systemWideThresholds.stream()
+ .map(InternalIoOveruseConfigurationSubject::toString)
+ .collect(Collectors.joining(", ")))
+ .append("]}");
+ return builder;
+ }
+
+ public static String toString(PerStateIoOveruseThreshold threshold) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{Name: ").append(threshold.name).append(", WriteBytes: {fgBytes: ")
+ .append(threshold.perStateWriteBytes.foregroundBytes).append(", bgBytes: ")
+ .append(threshold.perStateWriteBytes.backgroundBytes).append(", gmBytes: ")
+ .append(threshold.perStateWriteBytes.garageModeBytes).append("}}");
+ return builder.toString();
+ }
+
+ public static String toString(IoOveruseAlertThreshold threshold) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{durationInSeconds: ").append(threshold.durationInSeconds)
+ .append(", writtenBytesPerSecond: ").append(threshold.writtenBytesPerSecond)
+ .append("}");
+ return builder.toString();
+ }
+
+ private InternalIoOveruseConfigurationSubject(FailureMetadata failureMetadata,
+ @Nullable Iterable<IoOveruseConfiguration> iterableSubject) {
+ super(failureMetadata, iterableSubject);
+ this.mActual = iterableSubject;
+ }
+
+ private static boolean isPerStateThresholdEquals(List<PerStateIoOveruseThreshold> actual,
+ List<PerStateIoOveruseThreshold> expected) {
+ Set<String> actualStr = toPerStateThresholdStrings(actual);
+ Set<String> expectedStr = toPerStateThresholdStrings(expected);
+ return actualStr.equals(expectedStr);
+ }
+
+ private static boolean isAlertThresholdEquals(List<IoOveruseAlertThreshold> actual,
+ List<IoOveruseAlertThreshold> expected) {
+ Set<String> actualStr = toAlertThresholdStrings(actual);
+ Set<String> expectedStr = toAlertThresholdStrings(expected);
+ return actualStr.equals(expectedStr);
+ }
+
+ private static boolean isPerStateBytesEquals(PerStateBytes acutal, PerStateBytes expected) {
+ return acutal.foregroundBytes == expected.foregroundBytes
+ && acutal.backgroundBytes == expected.backgroundBytes
+ && acutal.garageModeBytes == expected.garageModeBytes;
+ }
+
+ private static Set<String> toPerStateThresholdStrings(
+ List<PerStateIoOveruseThreshold> thresholds) {
+ return thresholds.stream().map(x -> String.format("%s:{%d,%d,%d}", x.name,
+ x.perStateWriteBytes.foregroundBytes, x.perStateWriteBytes.backgroundBytes,
+ x.perStateWriteBytes.garageModeBytes))
+ .collect(Collectors.toSet());
+ }
+
+ private static Set<String> toAlertThresholdStrings(
+ List<IoOveruseAlertThreshold> thresholds) {
+ return thresholds.stream().map(x -> String.format("%d:%d", x.durationInSeconds,
+ x.writtenBytesPerSecond)).collect(Collectors.toSet());
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/InternalResourceOveruseConfigurationSubject.java b/tests/carservice_unit_test/src/com/android/car/watchdog/InternalResourceOveruseConfigurationSubject.java
new file mode 100644
index 0000000..d324efe
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/InternalResourceOveruseConfigurationSubject.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import android.annotation.Nullable;
+import android.automotive.watchdog.internal.PackageMetadata;
+import android.automotive.watchdog.internal.ResourceOveruseConfiguration;
+import android.automotive.watchdog.internal.ResourceSpecificConfiguration;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public final class InternalResourceOveruseConfigurationSubject extends Subject {
+ // Boiler-plate Subject.Factory for InternalResourceOveruseConfigurationSubject
+ private static final Subject.Factory<
+ com.android.car.watchdog.InternalResourceOveruseConfigurationSubject,
+ Iterable<ResourceOveruseConfiguration>> RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY =
+ com.android.car.watchdog.InternalResourceOveruseConfigurationSubject::new;
+
+ private static final Correspondence<List<PackageMetadata>, List<PackageMetadata>>
+ METADATA_LIST_CORRESPONDENCE = Correspondence.from(
+ InternalResourceOveruseConfigurationSubject::isPackageMetadataEquals,
+ "is equal to");
+
+ private static final Correspondence<List<ResourceSpecificConfiguration>,
+ List<ResourceSpecificConfiguration>>
+ RESOURCE_SPECIFIC_CONFIG_LIST_CORRESPONDENCE = Correspondence.from(
+ InternalResourceOveruseConfigurationSubject::isResourceSpecificConfigEquals,
+ "is equal to");
+
+ private final Iterable<ResourceOveruseConfiguration> mActual;
+
+ // User-defined entry point
+ public static InternalResourceOveruseConfigurationSubject assertThat(
+ @Nullable Iterable<ResourceOveruseConfiguration> stats) {
+ return assertAbout(RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY).that(stats);
+ }
+
+ public static Subject.Factory<InternalResourceOveruseConfigurationSubject,
+ Iterable<ResourceOveruseConfiguration>> resourceOveruseStats() {
+ return RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY;
+ }
+
+ public void containsExactly(ResourceOveruseConfiguration... stats) {
+ containsExactlyElementsIn(Arrays.asList(stats));
+ }
+
+ public void containsExactlyElementsIn(Iterable<ResourceOveruseConfiguration> expected) {
+ Truth.assertWithMessage("Expected: " + toString(expected) + "\nActual: "
+ + toString(mActual)).that(mActual)
+ .comparingElementsUsing(Correspondence.from(
+ InternalResourceOveruseConfigurationSubject::isEquals, "is equal to"))
+ .containsExactlyElementsIn(expected);
+ }
+
+ public static boolean isPackageMetadataEquals(List<PackageMetadata> actual,
+ List<PackageMetadata> expected) {
+ Set<String> actualStr = toMetadataStrings(actual);
+ Set<String> expectedStr = toMetadataStrings(expected);
+ return actualStr.equals(expectedStr);
+ }
+
+ public static boolean isResourceSpecificConfigEquals(List<ResourceSpecificConfiguration> actual,
+ List<ResourceSpecificConfiguration> expected) {
+ if (actual.size() != expected.size()) {
+ return false;
+ }
+ if (actual.size() == 0) {
+ return true;
+ }
+ /*
+ * When more resource types are added make this comparison more generic. Because the
+ * resource overuse configuration should contain only one I/O overuse configuration, the
+ * comparison only checks for first I/O overuse configuration.
+ */
+ ResourceSpecificConfiguration actualElement = actual.get(0);
+ ResourceSpecificConfiguration expectedElement = expected.get(0);
+ if (actualElement.getTag() != expectedElement.getTag()) {
+ return false;
+ }
+ if (actualElement.getTag() != ResourceSpecificConfiguration.ioOveruseConfiguration) {
+ return false;
+ }
+ return InternalIoOveruseConfigurationSubject.isEquals(
+ actualElement.getIoOveruseConfiguration(),
+ expectedElement.getIoOveruseConfiguration());
+ }
+
+ public static boolean isEquals(ResourceOveruseConfiguration actual,
+ ResourceOveruseConfiguration expected) {
+ if (actual == null || expected == null) {
+ return (actual == null) && (expected == null);
+ }
+ return actual.componentType == expected.componentType
+ && ImmutableSet.copyOf(actual.safeToKillPackages).equals(
+ ImmutableSet.copyOf(expected.safeToKillPackages))
+ && ImmutableSet.copyOf(actual.vendorPackagePrefixes).equals(
+ ImmutableSet.copyOf(expected.vendorPackagePrefixes))
+ && METADATA_LIST_CORRESPONDENCE.compare(actual.packageMetadata,
+ expected.packageMetadata)
+ && RESOURCE_SPECIFIC_CONFIG_LIST_CORRESPONDENCE.compare(
+ actual.resourceSpecificConfigurations,
+ expected.resourceSpecificConfigurations);
+ }
+
+ private InternalResourceOveruseConfigurationSubject(FailureMetadata failureMetadata,
+ @Nullable Iterable<ResourceOveruseConfiguration> iterableSubject) {
+ super(failureMetadata, iterableSubject);
+ this.mActual = iterableSubject;
+ }
+
+ private static Set<String> toMetadataStrings(List<PackageMetadata> metadata) {
+ return metadata.stream().map(x -> String.format("%s:%d", x.packageName, x.appCategoryType))
+ .collect(Collectors.toSet());
+ }
+
+ private static String toString(
+ Iterable<ResourceOveruseConfiguration> configs) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ for (ResourceOveruseConfiguration config : configs) {
+ toStringBuilder(builder, config).append(", ");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ private static StringBuilder toStringBuilder(StringBuilder builder,
+ ResourceOveruseConfiguration config) {
+ builder.append("{Component type: ").append(config.componentType)
+ .append(", Safe-to-kill packages: [")
+ .append(config.safeToKillPackages.stream().map(Object::toString)
+ .collect(Collectors.joining(", ")))
+ .append("], Vendor package prefixes: [")
+ .append(config.vendorPackagePrefixes.stream().map(Object::toString)
+ .collect(Collectors.joining(", ")))
+ .append("], Package Metadata: [")
+ .append(config.packageMetadata.stream()
+ .map(InternalResourceOveruseConfigurationSubject::toPackageMetadataString)
+ .collect(Collectors.joining(", ")))
+ .append("], Resource specific configurations: [")
+ .append(config.resourceSpecificConfigurations.stream()
+ .map(InternalResourceOveruseConfigurationSubject
+ ::toResourceOveruseConfigString).collect(Collectors.joining(", ")))
+ .append("]}");
+ return builder;
+ }
+
+ private static String toResourceOveruseConfigString(ResourceSpecificConfiguration config) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{Tag: ").append(config.getTag()).append(", Value: ");
+ if (config.getTag() == ResourceSpecificConfiguration.ioOveruseConfiguration) {
+ InternalIoOveruseConfigurationSubject.toStringBuilder(builder,
+ config.getIoOveruseConfiguration());
+ } else {
+ builder.append("UNKNOWN");
+ }
+ return builder.toString();
+ }
+
+ private static String toPackageMetadataString(PackageMetadata metadata) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{Name: ").append(metadata.packageName).append(", App category type: ")
+ .append(metadata.appCategoryType).append("}");
+ return builder.toString();
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/IoOveruseConfigurationSubject.java b/tests/carservice_unit_test/src/com/android/car/watchdog/IoOveruseConfigurationSubject.java
new file mode 100644
index 0000000..3629898
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/IoOveruseConfigurationSubject.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import android.annotation.Nullable;
+import android.car.watchdog.IoOveruseAlertThreshold;
+import android.car.watchdog.IoOveruseConfiguration;
+import android.car.watchdog.PerStateBytes;
+
+import com.google.common.base.Equivalence;
+import com.google.common.collect.Maps;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public final class IoOveruseConfigurationSubject extends Subject {
+ // Boiler-plate Subject.Factory for IoOveruseConfigurationSubject
+ private static final Subject.Factory<
+ com.android.car.watchdog.IoOveruseConfigurationSubject,
+ Iterable<IoOveruseConfiguration>> Io_OVERUSE_CONFIG_SUBJECT_FACTORY =
+ com.android.car.watchdog.IoOveruseConfigurationSubject::new;
+
+ private static final Equivalence<PerStateBytes> PER_STATE_BYTES_EQUIVALENCE =
+ new Equivalence<PerStateBytes>() {
+ @Override
+ protected boolean doEquivalent(PerStateBytes actual, PerStateBytes expected) {
+ return isPerStateBytesEquals(actual, expected);
+ }
+
+ @Override
+ protected int doHash(PerStateBytes perStateBytes) {
+ return (int) ((perStateBytes.getForegroundModeBytes() * 10 ^ 4)
+ + (perStateBytes.getBackgroundModeBytes() * 10 ^ 3)
+ + perStateBytes.getGarageModeBytes());
+ }
+ };
+
+ private final Iterable<IoOveruseConfiguration> mActual;
+
+ // User-defined entry point
+ public static IoOveruseConfigurationSubject assertThat(
+ @Nullable Iterable<IoOveruseConfiguration> stats) {
+ return assertAbout(Io_OVERUSE_CONFIG_SUBJECT_FACTORY).that(stats);
+ }
+
+ public static Subject.Factory<IoOveruseConfigurationSubject,
+ Iterable<IoOveruseConfiguration>> resourceOveruseStats() {
+ return Io_OVERUSE_CONFIG_SUBJECT_FACTORY;
+ }
+
+ public void containsExactly(IoOveruseConfiguration... stats) {
+ containsExactlyElementsIn(Arrays.asList(stats));
+ }
+
+ public void containsExactlyElementsIn(Iterable<IoOveruseConfiguration> expected) {
+ Truth.assertThat(mActual)
+ .comparingElementsUsing(Correspondence.from(
+ IoOveruseConfigurationSubject::isEquals, "is equal to"))
+ .containsExactlyElementsIn(expected);
+ }
+
+ public static boolean isEquals(IoOveruseConfiguration actual,
+ IoOveruseConfiguration expected) {
+ if (actual == null || expected == null) {
+ return (actual == null) && (expected == null);
+ }
+
+ return isPerStateBytesEquals(actual.getComponentLevelThresholds(),
+ expected.getComponentLevelThresholds())
+ && Maps.difference(actual.getPackageSpecificThresholds(),
+ expected.getPackageSpecificThresholds(), PER_STATE_BYTES_EQUIVALENCE).areEqual()
+ && Maps.difference(actual.getAppCategorySpecificThresholds(),
+ expected.getAppCategorySpecificThresholds(), PER_STATE_BYTES_EQUIVALENCE).areEqual()
+ && isAlertThresholdEquals(actual.getSystemWideThresholds(),
+ expected.getSystemWideThresholds());
+ }
+
+ private IoOveruseConfigurationSubject(FailureMetadata failureMetadata,
+ @Nullable Iterable<IoOveruseConfiguration> iterableSubject) {
+ super(failureMetadata, iterableSubject);
+ this.mActual = iterableSubject;
+ }
+
+ private static boolean isPerStateBytesEquals(PerStateBytes actual, PerStateBytes expected) {
+ return actual.getForegroundModeBytes() == expected.getForegroundModeBytes()
+ && actual.getBackgroundModeBytes() == expected.getBackgroundModeBytes()
+ && actual.getGarageModeBytes() == expected.getGarageModeBytes();
+ }
+
+ private static boolean isAlertThresholdEquals(List<IoOveruseAlertThreshold> actual,
+ List<IoOveruseAlertThreshold> expected) {
+ Set<String> actualStr = toAlertThresholdStrings(actual);
+ Set<String> expectedStr = toAlertThresholdStrings(expected);
+ return actualStr.equals(expectedStr);
+ }
+
+ private static Set<String> toAlertThresholdStrings(List<IoOveruseAlertThreshold> thresholds) {
+ return thresholds.stream().map(x -> String.format("%d:%d", x.getDurationInSeconds(),
+ x.getWrittenBytesPerSecond())).collect(Collectors.toSet());
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/PackageKillableStateSubject.java b/tests/carservice_unit_test/src/com/android/car/watchdog/PackageKillableStateSubject.java
new file mode 100644
index 0000000..953d1df
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/PackageKillableStateSubject.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import android.annotation.Nullable;
+import android.car.watchdog.PackageKillableState;
+
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+
+import java.util.Arrays;
+
+public final class PackageKillableStateSubject extends Subject {
+ // Boiler-plate Subject.Factory for PackageKillableStateSubject
+ private static final Subject.Factory<
+ com.android.car.watchdog.PackageKillableStateSubject,
+ Iterable<PackageKillableState>> PACKAGE_KILLABLE_STATE_SUBJECT_FACTORY =
+ com.android.car.watchdog.PackageKillableStateSubject::new;
+
+ private final Iterable<PackageKillableState> mActual;
+
+ // User-defined entry point
+ public static PackageKillableStateSubject assertThat(
+ @Nullable Iterable<PackageKillableState> stats) {
+ return assertAbout(PACKAGE_KILLABLE_STATE_SUBJECT_FACTORY).that(stats);
+ }
+
+ public static Subject.Factory<PackageKillableStateSubject,
+ Iterable<PackageKillableState>> resourceOveruseStats() {
+ return PACKAGE_KILLABLE_STATE_SUBJECT_FACTORY;
+ }
+
+ public void containsExactly(PackageKillableState... stats) {
+ containsExactlyElementsIn(Arrays.asList(stats));
+ }
+
+ public void containsExactlyElementsIn(Iterable<PackageKillableState> expected) {
+ Truth.assertThat(mActual)
+ .comparingElementsUsing(Correspondence.from(
+ PackageKillableStateSubject::isEquals, "is equal to"))
+ .containsExactlyElementsIn(expected);
+ }
+
+ public static boolean isEquals(PackageKillableState actual,
+ PackageKillableState expected) {
+ if (actual == null || expected == null) {
+ return (actual == null) && (expected == null);
+ }
+ return actual.getPackageName().equals(expected.getPackageName())
+ && actual.getUserId() == expected.getUserId()
+ && actual.getKillableState() == expected.getKillableState();
+ }
+
+ private PackageKillableStateSubject(FailureMetadata failureMetadata,
+ @Nullable Iterable<PackageKillableState> iterableSubject) {
+ super(failureMetadata, iterableSubject);
+ this.mActual = iterableSubject;
+ }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/watchdog/ResourceOveruseConfigurationSubject.java b/tests/carservice_unit_test/src/com/android/car/watchdog/ResourceOveruseConfigurationSubject.java
new file mode 100644
index 0000000..5bfdf17
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/watchdog/ResourceOveruseConfigurationSubject.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.watchdog;
+
+import static com.google.common.truth.Truth.assertAbout;
+
+import android.annotation.Nullable;
+import android.car.watchdog.ResourceOveruseConfiguration;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.truth.Correspondence;
+import com.google.common.truth.FailureMetadata;
+import com.google.common.truth.Subject;
+import com.google.common.truth.Truth;
+
+import java.util.Arrays;
+
+public final class ResourceOveruseConfigurationSubject extends Subject {
+ // Boiler-plate Subject.Factory for ResourceOveruseConfigurationSubject
+ private static final Subject.Factory<
+ com.android.car.watchdog.ResourceOveruseConfigurationSubject,
+ Iterable<ResourceOveruseConfiguration>> RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY =
+ com.android.car.watchdog.ResourceOveruseConfigurationSubject::new;
+
+ private final Iterable<ResourceOveruseConfiguration> mActual;
+
+ // User-defined entry point
+ public static ResourceOveruseConfigurationSubject assertThat(
+ @Nullable Iterable<ResourceOveruseConfiguration> stats) {
+ return assertAbout(RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY).that(stats);
+ }
+
+ public static Subject.Factory<ResourceOveruseConfigurationSubject,
+ Iterable<ResourceOveruseConfiguration>> resourceOveruseStats() {
+ return RESOURCE_OVERUSE_CONFIG_SUBJECT_FACTORY;
+ }
+
+ public void containsExactly(ResourceOveruseConfiguration... stats) {
+ containsExactlyElementsIn(Arrays.asList(stats));
+ }
+
+ public void containsExactlyElementsIn(Iterable<ResourceOveruseConfiguration> expected) {
+ Truth.assertThat(mActual)
+ .comparingElementsUsing(Correspondence.from(
+ ResourceOveruseConfigurationSubject::isEquals, "is equal to"))
+ .containsExactlyElementsIn(expected);
+ }
+
+ public static boolean isEquals(ResourceOveruseConfiguration actual,
+ ResourceOveruseConfiguration expected) {
+ if (actual == null || expected == null) {
+ return (actual == null) && (expected == null);
+ }
+ return actual.getComponentType() == expected.getComponentType()
+ && ImmutableSet.copyOf(actual.getSafeToKillPackages()).equals(
+ ImmutableSet.copyOf(expected.getSafeToKillPackages()))
+ && ImmutableSet.copyOf(actual.getVendorPackagePrefixes()).equals(
+ ImmutableSet.copyOf(expected.getVendorPackagePrefixes()))
+ && Maps.difference(actual.getPackagesToAppCategoryTypes(),
+ expected.getPackagesToAppCategoryTypes()).areEqual()
+ && IoOveruseConfigurationSubject.isEquals(actual.getIoOveruseConfiguration(),
+ expected.getIoOveruseConfiguration());
+ }
+
+ private ResourceOveruseConfigurationSubject(FailureMetadata failureMetadata,
+ @Nullable Iterable<ResourceOveruseConfiguration> iterableSubject) {
+ super(failureMetadata, iterableSubject);
+ this.mActual = iterableSubject;
+ }
+}