Merge "Improve YUY2 to RGBA color conversion" into sc-dev
diff --git a/.clang-format b/.clang-format
index 30e9eda..b652e19 100644
--- a/.clang-format
+++ b/.clang-format
@@ -36,3 +36,7 @@
- Regex: '^".*'
Priority: 1
---
+Language: Proto
+BasedOnStyle: Google
+ColumnLimit: 100
+---
diff --git a/car-lib/Android.bp b/car-lib/Android.bp
index 2112521..9c11299 100644
--- a/car-lib/Android.bp
+++ b/car-lib/Android.bp
@@ -153,7 +153,6 @@
droidstubs {
name: "android.car-stubs-docs",
defaults: ["android.car-docs-default"],
- removed_dex_api_filename: "removed-dex.txt",
args: "--hide UnavailableSymbol --no-docs --stub-packages android.car* " +
"--hide-package com.android.internal ",
installable: false,
@@ -182,7 +181,6 @@
droidstubs {
name: "android.car-system-stubs-docs",
defaults: ["android.car-docs-default"],
- removed_dex_api_filename: "system-removed-dex.txt",
// TODO(b/174572385): Remove CallbackInterface once this b/174572385 is fixed
args: "--hide CallbackInterface --hide UnavailableSymbol --hide HiddenSuperclass " +
"--no-docs --stub-packages android.car* " +
diff --git a/car-lib/src/android/car/VehiclePropertyIds.java b/car-lib/src/android/car/VehiclePropertyIds.java
index 0d93ff1..a677453 100644
--- a/car-lib/src/android/car/VehiclePropertyIds.java
+++ b/car-lib/src/android/car/VehiclePropertyIds.java
@@ -67,7 +67,7 @@
@RequiresPermission(Car.PERMISSION_CAR_INFO)
public static final int INFO_FUEL_TYPE = 289472773;
/**
- * Battery capacity of the vehicle, if EV or hybrid. This is the nominal
+ * Battery capacity of the vehicle in watt-hours (Wh), if EV or hybrid. This is the nominal
* battery capacity when the vehicle is new.
* Requires permission: {@link Car#PERMISSION_CAR_INFO}.
*/
@@ -130,19 +130,19 @@
@RequiresPermission(Car.PERMISSION_CAR_INFO)
public static final int INFO_EXTERIOR_DIMENSIONS = 289472779;
/**
- * Current odometer value of the vehicle
+ * Current odometer value of the vehicle in kilometers.
* The property is protected by the signature permission: android.car.permission.CAR_MILEAGE.
*/
@RequiresPermission(Car.PERMISSION_MILEAGE)
public static final int PERF_ODOMETER = 291504644;
/**
- * Speed of the vehicle
+ * Speed of the vehicle in meters per second.
* Requires permission: {@link Car#PERMISSION_SPEED}.
*/
@RequiresPermission(Car.PERMISSION_SPEED)
public static final int PERF_VEHICLE_SPEED = 291504647;
/**
- * Speed of the vehicle for displays
+ * Speed of the vehicle in meters per second for displays.
*
* Some cars display a slightly slower speed than the actual speed. This is
* usually displayed on the speedometer.
@@ -151,23 +151,23 @@
@RequiresPermission(Car.PERMISSION_SPEED)
public static final int PERF_VEHICLE_SPEED_DISPLAY = 291504648;
/**
- * Front bicycle model steering angle for vehicle
+ * Front bicycle model steering angle for vehicle in degrees.
*
- * Angle is in degrees. Left is negative.
+ * Left is negative.
* Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
*/
@RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
public static final int PERF_STEERING_ANGLE = 291504649;
/**
- * Rear bicycle model steering angle for vehicle
+ * Rear bicycle model steering angle for vehicle in degrees.
*
- * Angle is in degrees. Left is negative.
+ * Left is negative.
* Requires permission: {@link Car#PERMISSION_READ_STEERING_STATE}.
*/
@RequiresPermission(Car.PERMISSION_READ_STEERING_STATE)
public static final int PERF_REAR_STEERING_ANGLE = 291504656;
/**
- * Temperature of engine coolant
+ * Temperature of engine coolant in celsius.
* The property is protected by the signature permission:
* android.car.permission.CAR_ENGINE_DETAILED.
*/
@@ -181,7 +181,7 @@
@RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
public static final int ENGINE_OIL_LEVEL = 289407747;
/**
- * Temperature of engine oil
+ * Temperature of engine oil in celsius.
* The property is protected by the signature permission:
* android.car.permission.CAR_ENGINE_DETAILED.
*/
@@ -195,8 +195,44 @@
@RequiresPermission(Car.PERMISSION_CAR_ENGINE_DETAILED)
public static final int ENGINE_RPM = 291504901;
/**
- * Reports wheel ticks
- * Requires permission: {@link Car#PERMISSION_SPEED}.
+ * Reports wheel ticks.
+ *
+ * <p>WHEEL_TICK property is {@link VehiclePropertyAccess#Read} access,
+ * {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS} and returns a Long[] type
+ * value.
+ *
+ * <p>The first element in the array is a reset count. A reset indicates
+ * previous tick counts are not comparable with this and future ones. Some
+ * sort of discontinuity in tick counting has occurred.
+ *
+ * <p>The next four elements represent ticks for individual wheels in the
+ * following order: front left, front right, rear right, rear left. All
+ * tick counts are cumulative. Tick counts increment when the vehicle
+ * moves forward, and decrement when vehicles moves in reverse. The ticks
+ * should be reset to 0 when the vehicle is started by the user.
+ *
+ * <ul>
+ * <li>Long[0] = reset count
+ * <li>Long[1] = front left ticks
+ * <li>Long[2] = front right ticks
+ * <li>Long[3] = rear right ticks
+ * <li>Long[4] = rear left ticks
+ * </ul>
+ *
+ * <p>configArray is used to indicate the micrometers-per-wheel-tick value and
+ * which wheels are supported. configArray is set as follows:
+ *
+ * <ul>
+ * <li>configArray[0], bits [0:3] = supported wheels. Uses enum Wheel.
+ * <li>configArray[1] = micrometers per front left wheel tick
+ * <li>configArray[2] = micrometers per front right wheel tick
+ * <li>configArray[3] = micrometers per rear right wheel tick
+ * <li>configArray[4] = micrometers per rear left wheel tick
+ * </ul>
+ *
+ * <p>NOTE: If a wheel is not supported, its value is always 0.
+ *
+ * <p>Requires permission: {@link Car#PERMISSION_SPEED}.
*/
@RequiresPermission(Car.PERMISSION_SPEED)
public static final int WHEEL_TICK = 290521862;
@@ -216,7 +252,7 @@
@RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_CONTROL_ENERGY_PORTS))
public static final int FUEL_DOOR_OPEN = 287310600;
/**
- * EV battery level in WH, if EV or hybrid
+ * EV battery level in watt-hours (Wh), if EV or hybrid.
* Requires permission: {@link Car#PERMISSION_ENERGY}.
*/
@RequiresPermission(Car.PERMISSION_ENERGY)
@@ -256,7 +292,7 @@
@RequiresPermission.Write(@RequiresPermission(Car.PERMISSION_ADJUST_RANGE_REMAINING))
public static final int RANGE_REMAINING = 291504904;
/**
- * Tire pressure
+ * Tire pressure in kilopascals.
*
* min/max value indicates tire pressure sensor range. Each tire will have a separate min/max
* value denoted by its areaConfig.areaId.
@@ -358,7 +394,7 @@
@RequiresPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE)
public static final int HVAC_FAN_DIRECTION = 356517121;
/**
- * HVAC current temperature.
+ * HVAC current temperature in celsius.
* The property is protected by the signature permission:
* android.car.permission.CONTROL_CAR_CLIMATE.
*/
@@ -625,7 +661,7 @@
Car.PERMISSION_VENDOR_EXTENSION}))
public static final int FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 287311364;
/**
- * Outside temperature
+ * Outside temperature in celsius.
* Requires permission: {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT}.
*/
@RequiresPermission(Car.PERMISSION_EXTERIOR_ENVIRONMENT)
diff --git a/car-lib/src/android/car/hardware/CarPropertyValue.java b/car-lib/src/android/car/hardware/CarPropertyValue.java
index b280e7d..0f2a6bf 100644
--- a/car-lib/src/android/car/hardware/CarPropertyValue.java
+++ b/car-lib/src/android/car/hardware/CarPropertyValue.java
@@ -83,7 +83,10 @@
}
/**
- * Creates an instance of CarPropertyValue.
+ * Creates an instance of CarPropertyValue. The {@code timestamp} is the time in nanoseconds at
+ * which the event happened. For a given car property, each new CarPropertyValue should be
+ * monotonically increasing using the same time base as
+ * {@link SystemClock#elapsedRealtimeNanos()}.
*
* @param propertyId Property ID
* @param areaId Area ID of Property
@@ -189,7 +192,13 @@
}
/**
- * @return Elapsed time of CarPropertyValue since boot in nanoseconds
+ * Returns the timestamp in nanoseconds at which the CarPropertyValue happened. For a given car
+ * property, each new CarPropertyValue should be monotonically increasing using the same time
+ * base as {@link SystemClock#elapsedRealtimeNanos()}.
+ *
+ * <p>NOTE: Timestamp should be synchronized with other signals from the platform (e.g.
+ * {@link Location} and {@link SensorEvent} instances). Ideally, timestamp synchronization
+ * error should be below 1 millisecond.
*/
public long getTimestamp() {
return mTimestamp;
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index bd47263..4271756 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -108,7 +108,7 @@
}
}
- /** Read ON_CHANGE sensors */
+ /** Read ONCHANGE sensors. */
public static final float SENSOR_RATE_ONCHANGE = 0f;
/** Read sensors at the rate of 1 hertz */
public static final float SENSOR_RATE_NORMAL = 1f;
@@ -219,6 +219,9 @@
* <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC}</li>
* <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}</li>
* </ul>
+ * <b>Note:</b>If listener registers for updates for a
+ * {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE} property, it will receive the
+ * property's current value upon registration.
* See {@link CarPropertyConfig#getChangeMode()} for details.
* If rate is higher than {@link CarPropertyConfig#getMaxSampleRate()}, it will be registered
* with max sample rate.
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
index da34344..aa930a0 100644
--- a/car-lib/src/android/car/watchdog/CarWatchdogManager.java
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -184,6 +184,8 @@
@RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
public void registerClient(@NonNull @CallbackExecutor Executor executor,
@NonNull CarWatchdogClientCallback client, @TimeoutLengthEnum int timeout) {
+ Objects.requireNonNull(client, "Client must be non-null");
+ Objects.requireNonNull(executor, "Executor must be non-null");
synchronized (mLock) {
if (mRegisteredClient == client) {
return;
@@ -218,6 +220,7 @@
@SystemApi
@RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
public void unregisterClient(@NonNull CarWatchdogClientCallback client) {
+ Objects.requireNonNull(client, "Client must be non-null");
synchronized (mLock) {
if (mRegisteredClient != client) {
Log.w(TAG, "Cannot unregister the client. It has not been registered.");
@@ -249,6 +252,7 @@
@SystemApi
@RequiresPermission(Car.PERMISSION_USE_CAR_WATCHDOG)
public void tellClientAlive(@NonNull CarWatchdogClientCallback client, int sessionId) {
+ Objects.requireNonNull(client, "Client must be non-null");
boolean shouldReport;
synchronized (mLock) {
if (mRegisteredClient != client) {
diff --git a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
index 66485be..65a3fb1 100644
--- a/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
+++ b/car-lib/src/com/android/car/internal/common/EventLogTags.logtags
@@ -94,6 +94,7 @@
150126 car_user_svc_start_user_in_background_resp (user_id|1),(result|1)
150127 car_user_svc_stop_user_req (user_id|1)
150128 car_user_svc_stop_user_resp (user_id|1),(result|1)
+150129 car_user_svc_initial_user_info_req_complete (request_type|1)
150140 car_user_hal_initial_user_info_req (request_id|1),(request_type|1),(timeout|1)
150141 car_user_hal_initial_user_info_resp (request_id|1),(status|1),(action|1),(user_id|1),(flags|1),(safe_name|3),(user_locales|3)
diff --git a/car_product/build/preinstalled-packages-product-car-base.xml b/car_product/build/preinstalled-packages-product-car-base.xml
index 9437d63..e236c7e 100644
--- a/car_product/build/preinstalled-packages-product-car-base.xml
+++ b/car_product/build/preinstalled-packages-product-car-base.xml
@@ -37,6 +37,11 @@
<install-in user-type="SYSTEM" />
</install-in-user-type>
+ <!-- RemoteProvisioner app does not have any UI and will only be run as
+ a background service -->
+ <install-in-user-type package="com.android.remoteprovisioner">
+ <install-in user-type="SYSTEM" />
+ </install-in-user-type>
<!--
Apps that need to run on SYSTEM and evaluated by package owner.
Here the apps will have FULL and SYSTEM.
@@ -296,11 +301,18 @@
<install-in-user-type package="com.android.certinstaller">
<install-in user-type="FULL" />
</install-in-user-type>
+ <!-- TODO(b/189246976) STOPSHIP Remove for SYSTEM user since this package
+ is needed for SYSTEM user only if the device supports feature_device_admin
+ and it's used by some device owner APIs-->
<install-in-user-type package="com.android.pacprocessor">
<install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
</install-in-user-type>
+ <!-- TODO(b/189246976) STOPSHIP Remove for SYSTEM user same as previous
+ package -->
<install-in-user-type package="com.android.proxyhandler">
<install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
</install-in-user-type>
<install-in-user-type package="com.android.vpndialogs">
<install-in user-type="FULL" />
diff --git a/car_product/rro/CarRotaryImeRRO/Android.bp b/car_product/rro/CarRotaryImeRRO/Android.bp
new file mode 100644
index 0000000..c9f85b9
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/Android.bp
@@ -0,0 +1,25 @@
+// 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"],
+}
+android_app {
+ name: "CarRotaryImeRRO",
+ resource_dirs: ["res"],
+ platform_apis: true,
+ aaptflags: [
+ "--no-resource-deduping",
+ "--no-resource-removal"
+ ],
+}
diff --git a/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml b/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml
new file mode 100644
index 0000000..ba83fce
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.car.rotary.ime.rro">
+ <application android:hasCode="false"/>
+ <overlay android:targetName="CarRotaryController"
+ android:targetPackage="com.android.car.rotary"
+ android:resourcesMap="@xml/overlays"
+ android:isStatic="true" />
+</manifest>
diff --git a/car_product/rro/CarRotaryImeRRO/res/values/strings.xml b/car_product/rro/CarRotaryImeRRO/res/values/strings.xml
new file mode 100644
index 0000000..18a59cf
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+<resources>
+ <!-- Component name of rotary IME. Empty if none. Overlaid to use demo rotary IME. -->
+ <string name="rotary_input_method" translatable="false">com.android.car.rotaryime/.RotaryIme</string>
+</resources>
diff --git a/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml b/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml
new file mode 100644
index 0000000..2b425a5
--- /dev/null
+++ b/car_product/rro/CarRotaryImeRRO/res/xml/overlays.xml
@@ -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.
+ -->
+
+<overlay>
+ <item target="string/rotary_input_method" value="@string/rotary_input_method"/>
+</overlay>
diff --git a/cpp/bugreport/main.cpp b/cpp/bugreport/main.cpp
index 783eaa8..e867144 100644
--- a/cpp/bugreport/main.cpp
+++ b/cpp/bugreport/main.cpp
@@ -18,7 +18,6 @@
#include <android-base/errors.h>
#include <android-base/file.h>
-#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -131,7 +130,7 @@
error = writer->StartEntry(name.c_str(), 0);
if (error) {
- ALOGE("Failed to start entry %s", writer->ErrorCodeString(error));
+ ALOGE("Failed to start entry: [%d] %s", error, writer->ErrorCodeString(error));
return;
}
android::base::unique_fd fd(
@@ -157,7 +156,7 @@
}
error = writer->WriteBytes(buffer, bytes_read);
if (error) {
- ALOGE("WriteBytes() failed %s", ZipWriter::ErrorCodeString(error));
+ ALOGE("WriteBytes() failed: [%d] %s", error, ZipWriter::ErrorCodeString(error));
// fail immediately
return;
}
@@ -165,13 +164,13 @@
error = writer->FinishEntry();
if (error) {
- ALOGE("failed to finish entry %s", writer->ErrorCodeString(error));
+ ALOGW("failed to finish entry: [%d] %s", error, writer->ErrorCodeString(error));
continue;
}
}
error = writer->Finish();
if (error) {
- ALOGE("failed to finish zip writer %s", writer->ErrorCodeString(error));
+ ALOGW("Failed to finish zip writer to: [%d] %s", error, writer->ErrorCodeString(error));
}
}
@@ -386,12 +385,12 @@
ALOGI("capturing screen for display (%s) as %s", id_as_string.c_str(), filename.c_str());
int status = runCommand(10, "/system/bin/screencap", args);
if (status == 0) {
- LOG(INFO) << "Screenshot saved for display:" << id_as_string;
+ ALOGI("Screenshot saved for display: %s", id_as_string.c_str());
}
// add the file regardless of the exit status of the screencap util.
extra_files->push_back(filename);
- LOG(ERROR) << "Failed to take screenshot for display:" << id_as_string;
+ ALOGW("Failed to take screenshot for display: %s", id_as_string.c_str());
}
void takeScreenshot(const char* tmp_dir, std::vector<std::string>* extra_files) {
diff --git a/cpp/computepipe/aidl/Android.bp b/cpp/computepipe/aidl/Android.bp
index 0820223..2cf9ca1 100644
--- a/cpp/computepipe/aidl/Android.bp
+++ b/cpp/computepipe/aidl/Android.bp
@@ -10,7 +10,7 @@
"android/automotive/computepipe/*.aidl",
],
imports: [
- "android.hardware.graphics.common",
+ "android.hardware.graphics.common-V2",
],
stability: "vintf",
backend: {
diff --git a/cpp/evs/apps/default/Android.bp b/cpp/evs/apps/default/Android.bp
index ea6feff..3b393e1 100644
--- a/cpp/evs/apps/default/Android.bp
+++ b/cpp/evs/apps/default/Android.bp
@@ -40,7 +40,7 @@
shared_libs: [
"libbase",
- "libbinder",
+ "libbinder_ndk",
"libcutils",
"libutils",
"libui",
diff --git a/cpp/evs/apps/default/EvsStateControl.cpp b/cpp/evs/apps/default/EvsStateControl.cpp
index 5552deb..e3d9757 100644
--- a/cpp/evs/apps/default/EvsStateControl.cpp
+++ b/cpp/evs/apps/default/EvsStateControl.cpp
@@ -14,18 +14,19 @@
* limitations under the License.
*/
#include "EvsStateControl.h"
-#include "RenderDirectView.h"
-#include "RenderTopView.h"
-#include "RenderPixelCopy.h"
-#include "FormatConvert.h"
-#include <stdio.h>
-#include <string.h>
+#include "FormatConvert.h"
+#include "RenderDirectView.h"
+#include "RenderPixelCopy.h"
+#include "RenderTopView.h"
#include <android-base/logging.h>
-#include <inttypes.h>
+#include <android/binder_manager.h>
#include <utils/SystemClock.h>
-#include <binder/IServiceManager.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
using ::android::hardware::automotive::evs::V1_0::EvsResult;
using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -33,8 +34,7 @@
using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
static bool isSfReady() {
- const android::String16 serviceName("SurfaceFlinger");
- return android::defaultServiceManager()->checkService(serviceName) != nullptr;
+ return ::ndk::SpAIBinder(::AServiceManager_getService("SurfaceFlinger")).get() != nullptr;
}
// TODO: Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
diff --git a/cpp/evs/manager/1.1/HalCamera.cpp b/cpp/evs/manager/1.1/HalCamera.cpp
index c7018bf..e527840 100644
--- a/cpp/evs/manager/1.1/HalCamera.cpp
+++ b/cpp/evs/manager/1.1/HalCamera.cpp
@@ -488,7 +488,7 @@
}
-Return<EvsResult> HalCamera::unsetMaster(sp<VirtualCamera> virtualCamera) {
+Return<EvsResult> HalCamera::unsetMaster(const VirtualCamera* virtualCamera) {
if (mPrimaryClient.promote() != virtualCamera) {
return EvsResult::INVALID_ARG;
} else {
diff --git a/cpp/evs/manager/1.1/HalCamera.h b/cpp/evs/manager/1.1/HalCamera.h
index 57ceac2..1b05443 100644
--- a/cpp/evs/manager/1.1/HalCamera.h
+++ b/cpp/evs/manager/1.1/HalCamera.h
@@ -95,7 +95,7 @@
Return<void> doneWithFrame(const BufferDesc_1_1& buffer);
Return<EvsResult> setMaster(sp<VirtualCamera> virtualCamera);
Return<EvsResult> forceMaster(sp<VirtualCamera> virtualCamera);
- Return<EvsResult> unsetMaster(sp<VirtualCamera> virtualCamera);
+ Return<EvsResult> unsetMaster(const VirtualCamera* virtualCamera);
Return<EvsResult> setParameter(sp<VirtualCamera> virtualCamera,
CameraParam id, int32_t& value);
Return<EvsResult> getParameter(CameraParam id, int32_t& value);
diff --git a/cpp/evs/manager/1.1/test/fuzzer/Android.bp b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
index 3ac8924..aa2bc88 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/Android.bp
+++ b/cpp/evs/manager/1.1/test/fuzzer/Android.bp
@@ -49,6 +49,7 @@
fuzz_config: {
cc: [
"changyeon@google.com",
+ "garysungang@google.com",
"guodonghu@google.com",
"smara@google.com",
"zhaomingyin@google.com",
diff --git a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
index a528ff7..9ecc6e0 100644
--- a/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
+++ b/cpp/evs/manager/1.1/test/fuzzer/HalCameraFuzzer.cpp
@@ -188,7 +188,7 @@
if (!virtualCameras.empty()) {
uint32_t whichCam =
fdp.ConsumeIntegralInRange<uint32_t>(0, virtualCameras.size() - 1);
- halCamera->unsetMaster(virtualCameras[whichCam]);
+ halCamera->unsetMaster(virtualCameras[whichCam].get());
}
break;
}
diff --git a/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te b/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
index 93a6760..a7184ab 100644
--- a/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
+++ b/cpp/powerpolicy/sepolicy/private/carpowerpolicy.te
@@ -16,3 +16,6 @@
# Configuration for carpowerpolicyd to check car_service.
allow carpowerpolicyd carservice_service:service_manager find;
+
+# Allow reading and writing /sys/power/
+allow carpowerpolicyd sysfs_power:file rw_file_perms;
diff --git a/cpp/telemetry/script_executor/Android.bp b/cpp/telemetry/script_executor/Android.bp
index 734d4dd..78b639a 100644
--- a/cpp/telemetry/script_executor/Android.bp
+++ b/cpp/telemetry/script_executor/Android.bp
@@ -16,13 +16,47 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_library {
- name: "script_executor",
- srcs: [
- "src/LuaEngine.cpp",
- ],
- static_libs: [
- "liblua",
- ],
+cc_defaults {
+ name: "scriptexecutor_defaults",
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ static_libs: [
+ "libbase",
+ "liblog",
+ "liblua",
+ ],
}
+cc_library {
+ name: "libscriptexecutor",
+ defaults: [
+ "scriptexecutor_defaults",
+ ],
+ srcs: [
+ "src/JniUtils.cpp",
+ "src/LuaEngine.cpp",
+ "src/ScriptExecutorListener.cpp",
+ ],
+ shared_libs: [
+ "libnativehelper",
+ ],
+ // Allow dependents to use the header files.
+ export_include_dirs: [
+ "src",
+ ],
+}
+
+cc_library_shared {
+ name: "libscriptexecutorjniutils-test",
+ defaults: [
+ "scriptexecutor_defaults",
+ ],
+ srcs: [
+ "src/tests/JniUtilsTestHelper.cpp",
+ ],
+ shared_libs: [
+ "libnativehelper",
+ "libscriptexecutor",
+ ],
+}
diff --git a/cpp/telemetry/script_executor/src/JniUtils.cpp b/cpp/telemetry/script_executor/src/JniUtils.cpp
new file mode 100644
index 0000000..93c1af8
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "JniUtils.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle) {
+ lua_newtable(luaEngine->GetLuaState());
+ // null bundle object is allowed. We will treat it as an empty table.
+ if (bundle == nullptr) {
+ return;
+ }
+
+ // TODO(b/188832769): Consider caching some of these JNI references for
+ // performance reasons.
+ jclass bundleClass = env->FindClass("android/os/Bundle");
+ jmethodID getKeySetMethod = env->GetMethodID(bundleClass, "keySet", "()Ljava/util/Set;");
+ jobject keys = env->CallObjectMethod(bundle, getKeySetMethod);
+ jclass setClass = env->FindClass("java/util/Set");
+ jmethodID iteratorMethod = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+ jobject keySetIteratorObject = env->CallObjectMethod(keys, iteratorMethod);
+
+ jclass iteratorClass = env->FindClass("java/util/Iterator");
+ jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+ jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+ jclass booleanClass = env->FindClass("java/lang/Boolean");
+ jclass integerClass = env->FindClass("java/lang/Integer");
+ jclass numberClass = env->FindClass("java/lang/Number");
+ jclass stringClass = env->FindClass("java/lang/String");
+ // TODO(b/188816922): Handle more types such as float and integer arrays,
+ // and perhaps nested Bundles.
+
+ jmethodID getMethod =
+ env->GetMethodID(bundleClass, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
+
+ // Iterate over key set of the bundle one key at a time.
+ while (env->CallBooleanMethod(keySetIteratorObject, hasNextMethod)) {
+ // Read the value object that corresponds to this key.
+ jstring key = (jstring)env->CallObjectMethod(keySetIteratorObject, nextMethod);
+ jobject value = env->CallObjectMethod(bundle, getMethod, key);
+
+ // Get the value of the type, extract it accordingly from the bundle and
+ // push the extracted value and the key to the Lua table.
+ if (env->IsInstanceOf(value, booleanClass)) {
+ jmethodID boolMethod = env->GetMethodID(booleanClass, "booleanValue", "()Z");
+ bool boolValue = static_cast<bool>(env->CallBooleanMethod(value, boolMethod));
+ lua_pushboolean(luaEngine->GetLuaState(), boolValue);
+ } else if (env->IsInstanceOf(value, integerClass)) {
+ jmethodID intMethod = env->GetMethodID(integerClass, "intValue", "()I");
+ lua_pushinteger(luaEngine->GetLuaState(), env->CallIntMethod(value, intMethod));
+ } else if (env->IsInstanceOf(value, numberClass)) {
+ // Condense other numeric types using one class. Because lua supports only
+ // integer or double, and we handled integer in previous if clause.
+ jmethodID numberMethod = env->GetMethodID(numberClass, "doubleValue", "()D");
+ /* Pushes a double onto the stack */
+ lua_pushnumber(luaEngine->GetLuaState(), env->CallDoubleMethod(value, numberMethod));
+ } else if (env->IsInstanceOf(value, stringClass)) {
+ const char* rawStringValue = env->GetStringUTFChars((jstring)value, nullptr);
+ lua_pushstring(luaEngine->GetLuaState(), rawStringValue);
+ env->ReleaseStringUTFChars((jstring)value, rawStringValue);
+ } else {
+ // Other types are not implemented yet, skipping.
+ continue;
+ }
+
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ // table[rawKey] = value, where value is on top of the stack,
+ // and the table is the next element in the stack.
+ lua_setfield(luaEngine->GetLuaState(), /* idx= */ -2, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ }
+}
+
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/telemetry/script_executor/src/JniUtils.h b/cpp/telemetry/script_executor/src/JniUtils.h
new file mode 100644
index 0000000..c3ef677
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/JniUtils.h
@@ -0,0 +1,39 @@
+/*
+ * 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_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+#define CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
+
+#include "LuaEngine.h"
+#include "jni.h"
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+
+// Helper function which takes android.os.Bundle object in "bundle" argument
+// and converts it to Lua table on top of Lua stack. All key-value pairs are
+// converted to the corresponding key-value pairs of the Lua table as long as
+// the Bundle value types are supported. At this point, we support boolean,
+// integer, double and String types in Java.
+void PushBundleToLuaTable(JNIEnv* env, LuaEngine* luaEngine, jobject bundle);
+
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_TELEMETRY_SCRIPT_EXECUTOR_SRC_JNIUTILS_H_
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.cpp b/cpp/telemetry/script_executor/src/LuaEngine.cpp
index a8cace3..cc1d0b8 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.cpp
+++ b/cpp/telemetry/script_executor/src/LuaEngine.cpp
@@ -28,8 +28,7 @@
namespace telemetry {
namespace script_executor {
-LuaEngine::LuaEngine(std::unique_ptr<ScriptExecutorListener> listener) :
- mListener(std::move(listener)) {
+LuaEngine::LuaEngine() {
mLuaState = luaL_newstate();
luaL_openlibs(mLuaState);
}
@@ -38,6 +37,10 @@
lua_close(mLuaState);
}
+lua_State* LuaEngine::GetLuaState() {
+ return mLuaState;
+}
+
} // namespace script_executor
} // namespace telemetry
} // namespace automotive
diff --git a/cpp/telemetry/script_executor/src/LuaEngine.h b/cpp/telemetry/script_executor/src/LuaEngine.h
index 086dbfe..a0f3978 100644
--- a/cpp/telemetry/script_executor/src/LuaEngine.h
+++ b/cpp/telemetry/script_executor/src/LuaEngine.h
@@ -33,14 +33,15 @@
// Encapsulates Lua script execution environment.
class LuaEngine {
public:
- explicit LuaEngine(std::unique_ptr<ScriptExecutorListener> listener);
+ LuaEngine();
virtual ~LuaEngine();
+ // Returns pointer to Lua state object.
+ lua_State* GetLuaState();
+
private:
lua_State* mLuaState; // owned
-
- std::unique_ptr<ScriptExecutorListener> mListener;
};
} // namespace script_executor
diff --git a/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
new file mode 100644
index 0000000..9e2c43a
--- /dev/null
+++ b/cpp/telemetry/script_executor/src/tests/JniUtilsTestHelper.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 "JniUtils.h"
+#include "LuaEngine.h"
+#include "jni.h"
+
+#include <cstdint>
+#include <cstring>
+
+namespace android {
+namespace automotive {
+namespace telemetry {
+namespace script_executor {
+namespace {
+
+extern "C" {
+
+#include "lua.h"
+
+JNIEXPORT jlong JNICALL
+Java_com_android_car_telemetry_JniUtilsTest_nativeCreateLuaEngine(JNIEnv* env, jobject object) {
+ // Cast first to intptr_t to ensure int can hold the pointer without loss.
+ return static_cast<jlong>(reinterpret_cast<intptr_t>(new LuaEngine()));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeDestroyLuaEngine(
+ JNIEnv* env, jobject object, jlong luaEnginePtr) {
+ delete reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+}
+
+JNIEXPORT void JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativePushBundleToLuaTableCaller(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jobject bundle) {
+ PushBundleToLuaTable(env, reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr)),
+ bundle);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeGetObjectSize(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jint index) {
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ return lua_rawlen(engine->GetLuaState(), static_cast<int>(index));
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasBooleanValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jboolean value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isboolean(luaState, -1))
+ result = false;
+ else
+ result = static_cast<bool>(lua_toboolean(luaState, -1)) == static_cast<bool>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasIntValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jint value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isinteger(luaState, -1))
+ result = false;
+ else
+ result = lua_tointeger(luaState, -1) == static_cast<int>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasDoubleValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jdouble value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isnumber(luaState, -1))
+ result = false;
+ else
+ result = static_cast<double>(lua_tonumber(luaState, -1)) == static_cast<double>(value);
+ lua_pop(luaState, 1);
+ return result;
+}
+
+JNIEXPORT bool JNICALL Java_com_android_car_telemetry_JniUtilsTest_nativeHasStringValue(
+ JNIEnv* env, jobject object, jlong luaEnginePtr, jstring key, jstring value) {
+ const char* rawKey = env->GetStringUTFChars(key, nullptr);
+ LuaEngine* engine = reinterpret_cast<LuaEngine*>(static_cast<intptr_t>(luaEnginePtr));
+ // Assumes the table is on top of the stack.
+ auto* luaState = engine->GetLuaState();
+ lua_pushstring(luaState, rawKey);
+ env->ReleaseStringUTFChars(key, rawKey);
+ lua_gettable(luaState, -2);
+ bool result = false;
+ if (!lua_isstring(luaState, -1)) {
+ result = false;
+ } else {
+ std::string s = lua_tostring(luaState, -1);
+ const char* rawValue = env->GetStringUTFChars(value, nullptr);
+ result = strcmp(lua_tostring(luaState, -1), rawValue) == 0;
+ env->ReleaseStringUTFChars(value, rawValue);
+ }
+ lua_pop(luaState, 1);
+ return result;
+}
+
+} // extern "C"
+
+} // namespace
+} // namespace script_executor
+} // namespace telemetry
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/aidl/Android.bp b/cpp/watchdog/aidl/Android.bp
index 88b056a..ee13520 100644
--- a/cpp/watchdog/aidl/Android.bp
+++ b/cpp/watchdog/aidl/Android.bp
@@ -31,6 +31,7 @@
},
versions: [
"2",
+ "3",
],
}
@@ -48,6 +49,6 @@
},
},
imports: [
- "android.automotive.watchdog",
+ "android.automotive.watchdog-V3",
],
}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash
new file mode 100644
index 0000000..1c3bcca
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/.hash
@@ -0,0 +1 @@
+7012931db08df47dbc9d06d9864dbe9d511d7062
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl
new file mode 100644
index 0000000..6c260a0
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/BootPhase.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum BootPhase {
+ BOOT_COMPLETED = 1000,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl
new file mode 100644
index 0000000..d7c9255
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdog.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdog {
+ void registerClient(in android.automotive.watchdog.ICarWatchdogClient client, in android.automotive.watchdog.TimeoutLength timeout);
+ void unregisterClient(in android.automotive.watchdog.ICarWatchdogClient client);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void registerMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void unregisterMediator(in android.automotive.watchdog.ICarWatchdogClient mediator);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void registerMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void unregisterMonitor(in android.automotive.watchdog.ICarWatchdogMonitor monitor);
+ void tellClientAlive(in android.automotive.watchdog.ICarWatchdogClient client, in int sessionId);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void tellMediatorAlive(in android.automotive.watchdog.ICarWatchdogClient mediator, in int[] clientsNotResponding, in int sessionId);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void tellDumpFinished(in android.automotive.watchdog.ICarWatchdogMonitor monitor, in int pid);
+ /**
+ * @deprecated Calling this API will result in unsupported operation binder error.
+ */
+ void notifySystemStateChange(in android.automotive.watchdog.StateType type, in int arg1, in int arg2);
+ void addResourceOveruseListener(in android.automotive.watchdog.ResourceType[] resourceTypes, in android.automotive.watchdog.IResourceOveruseListener listener);
+ void removeResourceOveruseListener(in android.automotive.watchdog.IResourceOveruseListener listener);
+ List<android.automotive.watchdog.ResourceOveruseStats> getResourceOveruseStats(in android.automotive.watchdog.ResourceType[] resourceTypes);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl
new file mode 100644
index 0000000..a4a356d
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogClient.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface ICarWatchdogClient {
+ oneway void checkIfAlive(in int sessionId, in android.automotive.watchdog.TimeoutLength timeout);
+ oneway void prepareProcessTermination();
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl
new file mode 100644
index 0000000..ba196dc
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ICarWatchdogMonitor.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@VintfStability
+interface ICarWatchdogMonitor {
+ oneway void onClientsNotResponding(in int[] pids);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.aidl
new file mode 100644
index 0000000..a743cd0
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IResourceOveruseListener.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+interface IResourceOveruseListener {
+ oneway void onOveruse(in android.automotive.watchdog.ResourceOveruseStats resourceOveruseStats);
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl
new file mode 100644
index 0000000..698617c
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/IoOveruseStats.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+parcelable IoOveruseStats {
+ boolean killableOnOveruse;
+ android.automotive.watchdog.PerStateBytes remainingWriteBytes;
+ long startTime;
+ long durationInSeconds;
+ android.automotive.watchdog.PerStateBytes writtenBytes;
+ int totalOveruses;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl
new file mode 100644
index 0000000..a933421
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PerStateBytes.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+parcelable PerStateBytes {
+ long foregroundBytes;
+ long backgroundBytes;
+ long garageModeBytes;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl
new file mode 100644
index 0000000..1729027
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/PowerCycle.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum PowerCycle {
+ POWER_CYCLE_SHUTDOWN = 0,
+ POWER_CYCLE_SUSPEND = 1,
+ POWER_CYCLE_RESUME = 2,
+ NUM_POWER_CYLES = 3,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.aidl
new file mode 100644
index 0000000..3715025
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceOveruseStats.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@VintfStability
+union ResourceOveruseStats {
+ android.automotive.watchdog.IoOveruseStats ioOveruseStats;
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.aidl
new file mode 100644
index 0000000..8551e13
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/ResourceType.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum ResourceType {
+ IO = 0,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl
new file mode 100644
index 0000000..75a7ea1
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/StateType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum StateType {
+ POWER_CYCLE = 0,
+ USER_STATE = 1,
+ BOOT_PHASE = 2,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl
new file mode 100644
index 0000000..c109f96
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/TimeoutLength.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+@Backing(type="int") @VintfStability
+enum TimeoutLength {
+ TIMEOUT_CRITICAL = 0,
+ TIMEOUT_MODERATE = 1,
+ TIMEOUT_NORMAL = 2,
+}
diff --git a/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl
new file mode 100644
index 0000000..cd25321
--- /dev/null
+++ b/cpp/watchdog/aidl/aidl_api/android.automotive.watchdog/3/android/automotive/watchdog/UserState.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.automotive.watchdog;
+/**
+ * @deprecated System API specific copy available under android.automotive.watchdog.internal package.
+ */
+@Backing(type="int") @VintfStability
+enum UserState {
+ USER_STATE_STARTED = 0,
+ USER_STATE_STOPPED = 1,
+ NUM_USER_STATES = 2,
+}
diff --git a/cpp/watchdog/server/Android.bp b/cpp/watchdog/server/Android.bp
index a0d85b8..9b5b973 100644
--- a/cpp/watchdog/server/Android.bp
+++ b/cpp/watchdog/server/Android.bp
@@ -66,6 +66,7 @@
shared_libs: [
"libcutils",
"libprocessgroup",
+ "libtinyxml2",
"libwatchdog_package_info_resolver",
],
}
@@ -82,6 +83,7 @@
"src/IoOveruseMonitor.cpp",
"src/IoPerfCollection.cpp",
"src/LooperWrapper.cpp",
+ "src/OveruseConfigurationXmlHelper.cpp",
"src/ProcDiskStats.cpp",
"src/ProcPidStat.cpp",
"src/ProcStat.cpp",
@@ -95,6 +97,13 @@
],
}
+filegroup {
+ name: "watchdog_test_xml_files",
+ srcs: [
+ "tests/data/*.xml",
+ ],
+}
+
cc_test {
name: "libwatchdog_test",
defaults: [
@@ -108,6 +117,8 @@
"tests/IoOveruseMonitorTest.cpp",
"tests/IoPerfCollectionTest.cpp",
"tests/LooperStub.cpp",
+ "tests/OveruseConfigurationTestUtils.cpp",
+ "tests/OveruseConfigurationXmlHelperTest.cpp",
"tests/PackageInfoResolverTest.cpp",
"tests/ProcDiskStatsTest.cpp",
"tests/ProcPidDir.cpp",
@@ -128,6 +139,7 @@
"libwatchdog_process_service",
"libwatchdog_package_info_resolver",
],
+ data: [":watchdog_test_xml_files"],
}
cc_defaults {
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
new file mode 100644
index 0000000..f76bcc5
--- /dev/null
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.cpp
@@ -0,0 +1,474 @@
+/*
+ * 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 "carwatchdogd"
+
+#include "OveruseConfigurationXmlHelper.h"
+
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.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/IoOveruseAlertThreshold.h>
+#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <android/automotive/watchdog/internal/PackageMetadata.h>
+#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <android/automotive/watchdog/internal/ResourceSpecificConfiguration.h>
+
+#include <tinyxml2.h>
+
+#include <unordered_set>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+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::PackageMetadata;
+using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::android::base::EqualsIgnoreCase;
+using ::android::base::Error;
+using ::android::base::Join;
+using ::android::base::ParseInt;
+using ::android::base::Result;
+using ::android::base::StartsWith;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::Trim;
+using ::android::binder::Status;
+using ::tinyxml2::XML_SUCCESS;
+using ::tinyxml2::XMLDocument;
+using ::tinyxml2::XMLElement;
+
+namespace {
+constexpr const char kTagResourceOveruseConfiguration[] = "resourceOveruseConfiguration";
+constexpr const char kTagComponentType[] = "componentType";
+
+constexpr const char kTagSafeToKillPackages[] = "safeToKillPackages";
+constexpr const char kTagPackage[] = "package";
+
+constexpr const char kTagVendorPackagePrefixes[] = "vendorPackagePrefixes";
+constexpr const char kTagPackagePrefix[] = "packagePrefix";
+
+constexpr const char kTagPackageToAppCategoryTypes[] = "packagesToAppCategoryTypes";
+constexpr const char kTagPackageAppCategory[] = "packageAppCategory";
+
+constexpr const char kTagIoOveruseConfiguration[] = "ioOveruseConfiguration";
+constexpr const char kTagComponentLevelThresholds[] = "componentLevelThresholds";
+constexpr const char kTagPackageSpecificThresholds[] = "packageSpecificThresholds";
+constexpr const char kTagState[] = "state";
+constexpr const char kStateIdForegroundMode[] = "foreground_mode";
+constexpr const char kStateIdBackgroundMode[] = "background_mode";
+constexpr const char kStateIdGarageMode[] = "garage_mode";
+constexpr int kNumStates = 3;
+
+constexpr const char kTagAppCategorySpecificThresholds[] = "appCategorySpecificThresholds";
+constexpr const char kTagAppCategoryThreshold[] = "appCategoryThreshold";
+
+constexpr const char kTagSystemWideThresholds[] = "systemWideThresholds";
+constexpr const char kTagParam[] = "param";
+constexpr const char kParamIdDurationSeconds[] = "duration_seconds";
+constexpr const char kParamIdWrittenBytesPerSecond[] = "written_bytes_per_second";
+constexpr int kNumParams = 2;
+
+constexpr const char kAttrId[] = "id";
+constexpr const char kAttrType[] = "type";
+
+Result<const XMLElement*> readExactlyOneElement(const char* tag, const XMLElement* rootElement) {
+ const XMLElement* element = rootElement->FirstChildElement(tag);
+ if (element == nullptr) {
+ return Error() << "Must specify value for the tag '" << tag << "'";
+ }
+ if (element->NextSiblingElement(tag) != nullptr) {
+ return Error() << "Must specify only one entry for the tag '" << tag << "'";
+ }
+ return element;
+}
+
+Result<ComponentType> readComponentType(const XMLElement* rootElement) {
+ const XMLElement* componentTypeElement;
+ if (const auto result = readExactlyOneElement(kTagComponentType, rootElement); result.ok()) {
+ componentTypeElement = *result;
+ } else {
+ return Error() << "Failed to read tag '" << kTagComponentType << "': " << result.error();
+ }
+ std::string componentTypeStr;
+ if (const auto text = componentTypeElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty component type";
+ } else if (componentTypeStr = Trim(text); componentTypeStr.empty()) {
+ return Error() << "Must specify non-empty component type";
+ }
+ static const std::string* const kSystemComponent =
+ new std::string(toString(ComponentType::SYSTEM));
+ static const std::string* const kVendorComponent =
+ new std::string(toString(ComponentType::VENDOR));
+ static const std::string* const kThirdPartyComponent =
+ new std::string(toString(ComponentType::THIRD_PARTY));
+ if (EqualsIgnoreCase(componentTypeStr, *kSystemComponent)) {
+ return ComponentType::SYSTEM;
+ } else if (EqualsIgnoreCase(componentTypeStr, *kVendorComponent)) {
+ return ComponentType::VENDOR;
+ } else if (EqualsIgnoreCase(componentTypeStr, *kThirdPartyComponent)) {
+ return ComponentType::THIRD_PARTY;
+ }
+ return Error() << "Must specify valid component type. Received " << componentTypeStr;
+}
+
+Result<std::vector<std::string>> readSafeToKillPackages(const XMLElement* rootElement) {
+ std::vector<std::string> safeToKillPackages;
+ for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagSafeToKillPackages);
+ outerElement != nullptr;
+ outerElement = outerElement->NextSiblingElement(kTagSafeToKillPackages)) {
+ for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagPackage);
+ innerElement != nullptr;
+ innerElement = innerElement->NextSiblingElement(kTagPackage)) {
+ std::string packageName;
+ if (const auto text = innerElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty safe-to-kill package name";
+ } else if (packageName = Trim(text); packageName.empty()) {
+ return Error() << "Must specify non-empty safe-to-kill package name";
+ }
+ safeToKillPackages.push_back(std::string(packageName));
+ }
+ }
+ return safeToKillPackages;
+}
+
+Result<std::vector<std::string>> readVendorPackagePrefixes(const XMLElement* rootElement) {
+ std::vector<std::string> vendorPackagePrefixes;
+ for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagVendorPackagePrefixes);
+ outerElement != nullptr;
+ outerElement = outerElement->NextSiblingElement(kTagVendorPackagePrefixes)) {
+ for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagPackagePrefix);
+ innerElement != nullptr;
+ innerElement = innerElement->NextSiblingElement(kTagPackagePrefix)) {
+ std::string packagePrefix;
+ if (const auto text = innerElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty vendor package prefix";
+ } else if (packagePrefix = Trim(text); packagePrefix.empty()) {
+ return Error() << "Must specify non-empty vendor package prefix";
+ }
+ vendorPackagePrefixes.push_back(std::string(packagePrefix));
+ }
+ }
+ return vendorPackagePrefixes;
+}
+
+ApplicationCategoryType toApplicationCategoryType(std::string_view value) {
+ static const std::string* const kMapsAppCategory =
+ new std::string(toString(ApplicationCategoryType::MAPS));
+ static const std::string* const kMediaAppCategory =
+ new std::string(toString(ApplicationCategoryType::MEDIA));
+ if (EqualsIgnoreCase(value, *kMapsAppCategory)) {
+ return ApplicationCategoryType::MAPS;
+ } else if (EqualsIgnoreCase(value, *kMediaAppCategory)) {
+ return ApplicationCategoryType::MEDIA;
+ }
+ return ApplicationCategoryType::OTHERS;
+}
+
+Result<std::vector<PackageMetadata>> readPackageToAppCategoryTypes(const XMLElement* rootElement) {
+ std::vector<PackageMetadata> packageMetadata;
+ for (const XMLElement* outerElement =
+ rootElement->FirstChildElement(kTagPackageToAppCategoryTypes);
+ outerElement != nullptr;
+ outerElement = outerElement->NextSiblingElement(kTagPackageToAppCategoryTypes)) {
+ for (const XMLElement* innerElement =
+ outerElement->FirstChildElement(kTagPackageAppCategory);
+ innerElement != nullptr;
+ innerElement = innerElement->NextSiblingElement(kTagPackageAppCategory)) {
+ const char* type = nullptr;
+ if (innerElement->QueryStringAttribute(kAttrType, &type) != XML_SUCCESS) {
+ return Error() << "Failed to read '" << kAttrType << "' attribute in '"
+ << kTagPackageAppCategory << "' tag";
+ }
+ PackageMetadata meta;
+ if (meta.appCategoryType = toApplicationCategoryType(type);
+ meta.appCategoryType == ApplicationCategoryType::OTHERS) {
+ return Error() << "Must specify valid app category type. Received " << type;
+ }
+ if (const auto text = innerElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty package name";
+ } else if (meta.packageName = Trim(text); meta.packageName.empty()) {
+ return Error() << "Must specify non-empty package name";
+ }
+ packageMetadata.push_back(meta);
+ }
+ }
+ return packageMetadata;
+}
+
+Result<PerStateBytes> readPerStateBytes(const XMLElement* rootElement) {
+ PerStateBytes perStateBytes;
+ std::unordered_set<std::string> seenStates;
+ for (const XMLElement* childElement = rootElement->FirstChildElement(kTagState);
+ childElement != nullptr; childElement = childElement->NextSiblingElement(kTagState)) {
+ const char* state = nullptr;
+ if (childElement->QueryStringAttribute(kAttrId, &state) != XML_SUCCESS) {
+ return Error() << "Failed to read '" << kAttrId << "' attribute in '" << kTagState
+ << "' tag";
+ }
+ if (seenStates.find(state) != seenStates.end()) {
+ return Error() << "Duplicate threshold specified for state '" << state << "'";
+ }
+ int64_t bytes = 0;
+ if (const auto text = childElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty threshold for state '" << state << "'";
+ } else if (const auto bytesStr = Trim(text); !ParseInt(bytesStr.c_str(), &bytes)) {
+ return Error() << "Failed to parse threshold for the state '" << state
+ << "': Received threshold value '" << bytesStr << "'";
+ }
+ if (!strcmp(state, kStateIdForegroundMode)) {
+ seenStates.insert(kStateIdForegroundMode);
+ perStateBytes.foregroundBytes = bytes;
+ } else if (!strcmp(state, kStateIdBackgroundMode)) {
+ seenStates.insert(kStateIdBackgroundMode);
+ perStateBytes.backgroundBytes = bytes;
+ } else if (!strcmp(state, kStateIdGarageMode)) {
+ seenStates.insert(kStateIdGarageMode);
+ perStateBytes.garageModeBytes = bytes;
+ } else {
+ return Error() << "Invalid state '" << state << "' in per-state bytes";
+ }
+ }
+ if (seenStates.size() != kNumStates) {
+ return Error() << "Thresholds not specified for all states. Specified only for ["
+ << Join(seenStates, ", ") << "] states";
+ }
+ return perStateBytes;
+}
+
+Result<PerStateIoOveruseThreshold> readComponentLevelThresholds(ComponentType componentType,
+ const XMLElement* rootElement) {
+ const XMLElement* componentLevelThresholdElement = nullptr;
+ if (const auto result = readExactlyOneElement(kTagComponentLevelThresholds, rootElement);
+ result.ok()) {
+ componentLevelThresholdElement = *result;
+ } else {
+ return Error() << "Failed to read tag '" << kTagComponentLevelThresholds
+ << "': " << result.error();
+ }
+ PerStateIoOveruseThreshold thresholds;
+ thresholds.name = toString(componentType);
+ if (const auto result = readPerStateBytes(componentLevelThresholdElement); result.ok()) {
+ thresholds.perStateWriteBytes = *result;
+ } else {
+ return Error() << "Failed to read component level thresholds for component '"
+ << thresholds.name << "': " << result.error();
+ }
+ return thresholds;
+}
+
+Result<std::vector<PerStateIoOveruseThreshold>> readPackageSpecificThresholds(
+ const XMLElement* rootElement) {
+ std::vector<PerStateIoOveruseThreshold> thresholds;
+ for (const XMLElement* childElement =
+ rootElement->FirstChildElement(kTagPackageSpecificThresholds);
+ childElement != nullptr;
+ childElement = childElement->NextSiblingElement(kTagPackageSpecificThresholds)) {
+ PerStateIoOveruseThreshold threshold;
+ if (const char* name = nullptr;
+ childElement->QueryStringAttribute(kAttrId, &name) != XML_SUCCESS) {
+ return Error() << "Failed to read '" << kAttrId << "' attribute in '"
+ << kTagPackageSpecificThresholds << "' tag";
+ } else if (threshold.name = name; threshold.name.empty()) {
+ return Error() << "Must provide non-empty package name in '" << kAttrId
+ << "attribute in '" << kTagPackageSpecificThresholds << "' tag";
+ }
+ if (const auto result = readPerStateBytes(childElement); result.ok()) {
+ threshold.perStateWriteBytes = *result;
+ } else {
+ return Error() << "Failed to read package specific thresholds for package '"
+ << threshold.name << "': " << result.error();
+ }
+ thresholds.push_back(threshold);
+ }
+ return thresholds;
+}
+
+Result<std::vector<PerStateIoOveruseThreshold>> readAppCategorySpecificThresholds(
+ const XMLElement* rootElement) {
+ std::vector<PerStateIoOveruseThreshold> thresholds;
+ for (const XMLElement* outerElement =
+ rootElement->FirstChildElement(kTagAppCategorySpecificThresholds);
+ outerElement != nullptr;
+ outerElement = outerElement->NextSiblingElement(kTagAppCategorySpecificThresholds)) {
+ for (const XMLElement* innerElement =
+ outerElement->FirstChildElement(kTagAppCategoryThreshold);
+ innerElement != nullptr;
+ innerElement = innerElement->NextSiblingElement(kTagAppCategoryThreshold)) {
+ const char* name = nullptr;
+ if (innerElement->QueryStringAttribute(kAttrId, &name) != XML_SUCCESS) {
+ return Error() << "Failed to read '" << kAttrId << "' attribute in '"
+ << kTagAppCategoryThreshold << "' tag";
+ }
+ PerStateIoOveruseThreshold threshold;
+ threshold.name = name;
+ if (const auto result = readPerStateBytes(innerElement); result.ok()) {
+ threshold.perStateWriteBytes = *result;
+ } else {
+ return Error() << "Failed to read app category specific thresholds for application "
+ << "category '" << threshold.name << "': " << result.error();
+ }
+ thresholds.push_back(threshold);
+ }
+ }
+ return thresholds;
+}
+
+Result<std::vector<IoOveruseAlertThreshold>> readSystemWideThresholds(
+ const XMLElement* rootElement) {
+ std::vector<IoOveruseAlertThreshold> alertThresholds;
+ for (const XMLElement* outerElement = rootElement->FirstChildElement(kTagSystemWideThresholds);
+ outerElement != nullptr;
+ outerElement = outerElement->NextSiblingElement(kTagSystemWideThresholds)) {
+ IoOveruseAlertThreshold alertThreshold;
+ std::unordered_set<std::string> seenParams;
+ for (const XMLElement* innerElement = outerElement->FirstChildElement(kTagParam);
+ innerElement != nullptr; innerElement = innerElement->NextSiblingElement(kTagParam)) {
+ const char* param = nullptr;
+ if (innerElement->QueryStringAttribute(kAttrId, ¶m) != XML_SUCCESS) {
+ return Error() << "Failed to read '" << kAttrId << "' attribute in '" << kTagParam
+ << "' tag";
+ }
+ if (seenParams.find(param) != seenParams.end()) {
+ return Error() << "Duplicate threshold specified for param '" << param << "'";
+ }
+ int64_t value = 0;
+ if (const auto text = innerElement->GetText(); text == nullptr) {
+ return Error() << "Must specify non-empty threshold for param '" << param << "'";
+ } else if (const auto valueStr = Trim(text); !ParseInt(valueStr.c_str(), &value)) {
+ return Error() << "Failed to parse threshold for the param '" << param
+ << "': Received threshold value '" << valueStr << "'";
+ }
+ if (!strcmp(param, kParamIdDurationSeconds)) {
+ seenParams.insert(kParamIdDurationSeconds);
+ alertThreshold.durationInSeconds = value;
+ } else if (!strcmp(param, kParamIdWrittenBytesPerSecond)) {
+ seenParams.insert(kParamIdWrittenBytesPerSecond);
+ alertThreshold.writtenBytesPerSecond = value;
+ } else {
+ return Error() << "Invalid param '" << param << "' in I/O overuse alert thresholds";
+ }
+ }
+ if (seenParams.size() != kNumParams) {
+ return Error() << "Thresholds not specified for all params. Specified only for ["
+ << Join(seenParams, ", ") << "] params";
+ }
+ alertThresholds.push_back(alertThreshold);
+ }
+ return alertThresholds;
+}
+
+Result<IoOveruseConfiguration> readIoOveruseConfiguration(ComponentType componentType,
+ const XMLElement* rootElement) {
+ const XMLElement* childElement = nullptr;
+ if (const auto result = readExactlyOneElement(kTagIoOveruseConfiguration, rootElement);
+ result.ok()) {
+ childElement = *result;
+ } else {
+ return Error() << "Failed to read tag '" << kTagIoOveruseConfiguration
+ << "': " << result.error();
+ }
+ IoOveruseConfiguration configuration;
+ if (const auto result = readComponentLevelThresholds(componentType, childElement);
+ result.ok()) {
+ configuration.componentLevelThresholds = *result;
+ } else {
+ return Error() << "Failed to read component-level thresholds: " << result.error();
+ }
+ if (const auto result = readPackageSpecificThresholds(childElement); result.ok()) {
+ configuration.packageSpecificThresholds = *result;
+ } else {
+ return Error() << "Failed to read package specific thresholds: " << result.error();
+ }
+ if (const auto result = readAppCategorySpecificThresholds(childElement); result.ok()) {
+ configuration.categorySpecificThresholds = *result;
+ } else {
+ return Error() << "Failed to read category specific thresholds: " << result.error();
+ }
+ if (const auto result = readSystemWideThresholds(childElement); result.ok()) {
+ configuration.systemWideThresholds = *result;
+ } else {
+ return Error() << "Failed to read system-wide thresholds: " << result.error();
+ }
+ return configuration;
+}
+
+} // namespace
+
+Result<ResourceOveruseConfiguration> OveruseConfigurationXmlHelper::parseXmlFile(
+ const char* filePath) {
+ XMLDocument xmlDoc;
+ xmlDoc.LoadFile(filePath);
+ if (xmlDoc.ErrorID() != XML_SUCCESS) {
+ return Error() << "Failed to read and/or parse '" << filePath << "'";
+ }
+ ResourceOveruseConfiguration configuration;
+ const XMLElement* rootElement = xmlDoc.RootElement();
+ if (!rootElement || strcmp(rootElement->Name(), kTagResourceOveruseConfiguration)) {
+ return Error() << "XML file doesn't have the root element '"
+ << kTagResourceOveruseConfiguration << "'";
+ }
+ if (const auto result = readComponentType(rootElement); result.ok()) {
+ configuration.componentType = *result;
+ } else {
+ return Error() << "Failed to read component type: " << result.error();
+ }
+ if (const auto result = readSafeToKillPackages(rootElement); result.ok()) {
+ configuration.safeToKillPackages = *result;
+ } else {
+ return Error() << "Failed to read safe-to-kill packages: " << result.error();
+ }
+ if (const auto result = readVendorPackagePrefixes(rootElement); result.ok()) {
+ configuration.vendorPackagePrefixes = *result;
+ } else {
+ return Error() << "Failed to read vendor package prefixes: " << result.error();
+ }
+ if (const auto result = readPackageToAppCategoryTypes(rootElement); result.ok()) {
+ configuration.packageMetadata = *result;
+ } else {
+ return Error() << "Failed to read package to app category types: " << result.error();
+ }
+ if (const auto result = readIoOveruseConfiguration(configuration.componentType, rootElement);
+ result.ok()) {
+ configuration.resourceSpecificConfigurations.emplace_back(
+ ResourceSpecificConfiguration(*result));
+ } else {
+ return Error() << "Failed to read I/O overuse configuration: " << result.error();
+ }
+ return configuration;
+}
+
+Result<void> OveruseConfigurationXmlHelper::writeXmlFile(
+ [[maybe_unused]] const ResourceOveruseConfiguration& configuration,
+ [[maybe_unused]] const char* filePath) {
+ // TODO(b/185287136): Write the configuration to file.
+ return {};
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
new file mode 100644
index 0000000..9f501c4
--- /dev/null
+++ b/cpp/watchdog/server/src/OveruseConfigurationXmlHelper.h
@@ -0,0 +1,44 @@
+/*
+ * 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_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
+#define CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
+
+#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+class OveruseConfigurationXmlHelper : public android::RefBase {
+public:
+ static android::base::Result<
+ android::automotive::watchdog::internal::ResourceOveruseConfiguration>
+ parseXmlFile(const char* filePath);
+
+ static android::base::Result<void> writeXmlFile(
+ const android::automotive::watchdog::internal::ResourceOveruseConfiguration&
+ configuration,
+ const char* filePath);
+};
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_WATCHDOG_SERVER_SRC_OVERUSECONFIGURATIONXMLHELPER_H_
diff --git a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
index 433f027..43d08d7 100644
--- a/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
+++ b/cpp/watchdog/server/tests/IoOveruseConfigsTest.cpp
@@ -15,6 +15,7 @@
*/
#include "IoOveruseConfigs.h"
+#include "OveruseConfigurationTestUtils.h"
#include <android-base/strings.h>
#include <gmock/gmock.h>
@@ -32,41 +33,18 @@
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 {
-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,
- const int64_t writtenBytesPerSecond) {
- IoOveruseAlertThreshold threshold;
- threshold.durationInSeconds = durationInSeconds;
- threshold.writtenBytesPerSecond = writtenBytesPerSecond;
- return threshold;
-}
-
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);
@@ -80,43 +58,6 @@
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;
@@ -137,35 +78,6 @@
return packageInfo;
}
-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, "[");
@@ -179,58 +91,11 @@
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(
+std::vector<Matcher<const ResourceOveruseConfiguration>> ResourceOveruseConfigurationsMatchers(
const std::vector<ResourceOveruseConfiguration>& configs) {
std::vector<Matcher<const ResourceOveruseConfiguration>> matchers;
for (const auto config : configs) {
- matchers.push_back(IsResourceOveruseConfiguration(config));
+ matchers.push_back(ResourceOveruseConfigurationMatcher(config));
}
return matchers;
}
@@ -313,7 +178,7 @@
std::vector<ResourceOveruseConfiguration> actual;
ioOveruseConfigs.get(&actual);
- EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
<< "Expected: " << toString(expected) << "Actual:" << toString(actual);
// Check whether previous configs are overwritten.
@@ -379,7 +244,7 @@
actual.clear();
ioOveruseConfigs.get(&actual);
- EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
<< "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
@@ -558,7 +423,7 @@
std::vector<ResourceOveruseConfiguration> actual;
ioOveruseConfigs.get(&actual);
- EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
<< "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
@@ -597,7 +462,7 @@
std::vector<ResourceOveruseConfiguration> actual;
ioOveruseConfigs.get(&actual);
- EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
<< "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
@@ -636,7 +501,7 @@
std::vector<ResourceOveruseConfiguration> actual;
ioOveruseConfigs.get(&actual);
- EXPECT_THAT(actual, UnorderedElementsAreArray(IsResourceOveruseConfigurations(expected)))
+ EXPECT_THAT(actual, UnorderedElementsAreArray(ResourceOveruseConfigurationsMatchers(expected)))
<< "Expected: " << toString(expected) << "Actual:" << toString(actual);
}
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
new file mode 100644
index 0000000..ec5908a
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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 "OveruseConfigurationTestUtils.h"
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+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::PackageMetadata;
+using ::android::automotive::watchdog::internal::PerStateIoOveruseThreshold;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+using ::android::automotive::watchdog::internal::ResourceSpecificConfiguration;
+using ::testing::AllOf;
+using ::testing::ExplainMatchResult;
+using ::testing::Field;
+using ::testing::Matcher;
+using ::testing::UnorderedElementsAreArray;
+
+namespace {
+
+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;
+ }
+}
+
+} // namespace
+
+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;
+}
+
+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;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+ const PerStateBytes& perStateBytes) {
+ PerStateIoOveruseThreshold threshold;
+ threshold.name = name;
+ threshold.perStateWriteBytes = perStateBytes;
+ return threshold;
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const std::string& name,
+ const int64_t fgBytes,
+ const int64_t bgBytes,
+ const int64_t garageModeBytes) {
+ return toPerStateIoOveruseThreshold(name, toPerStateBytes(fgBytes, bgBytes, garageModeBytes));
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+ const PerStateBytes& perStateBytes) {
+ return toPerStateIoOveruseThreshold(toString(type), perStateBytes);
+}
+
+PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(const ComponentType type,
+ const int64_t fgBytes,
+ const int64_t bgBytes,
+ const int64_t garageModeBytes) {
+ return toPerStateIoOveruseThreshold(type, toPerStateBytes(fgBytes, bgBytes, garageModeBytes));
+}
+
+PackageMetadata toPackageMetadata(std::string packageName, ApplicationCategoryType type) {
+ PackageMetadata meta;
+ meta.packageName = packageName;
+ meta.appCategoryType = type;
+ return meta;
+}
+
+IoOveruseAlertThreshold toIoOveruseAlertThreshold(const int64_t durationInSeconds,
+ const int64_t writtenBytesPerSecond) {
+ IoOveruseAlertThreshold threshold;
+ threshold.durationInSeconds = durationInSeconds;
+ threshold.writtenBytesPerSecond = writtenBytesPerSecond;
+ return threshold;
+}
+
+Matcher<const ResourceOveruseConfiguration> ResourceOveruseConfigurationMatcher(
+ 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)));
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
new file mode 100644
index 0000000..84c970a
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationTestUtils.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
+#define CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_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/IoOveruseAlertThreshold.h>
+#include <android/automotive/watchdog/internal/IoOveruseConfiguration.h>
+#include <android/automotive/watchdog/internal/PackageMetadata.h>
+#include <android/automotive/watchdog/internal/PerStateIoOveruseThreshold.h>
+#include <android/automotive/watchdog/internal/ResourceOveruseConfiguration.h>
+#include <gmock/gmock.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+android::automotive::watchdog::internal::ResourceOveruseConfiguration
+constructResourceOveruseConfig(
+ const android::automotive::watchdog::internal::ComponentType type,
+ const std::vector<std::string>&& safeToKill,
+ const std::vector<std::string>&& vendorPrefixes,
+ const std::vector<android::automotive::watchdog::internal::PackageMetadata> packageMetadata,
+ const android::automotive::watchdog::internal::IoOveruseConfiguration&
+ ioOveruseConfiguration);
+
+android::automotive::watchdog::internal::IoOveruseConfiguration constructIoOveruseConfig(
+ android::automotive::watchdog::internal::PerStateIoOveruseThreshold componentLevel,
+ const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+ packageSpecific,
+ const std::vector<android::automotive::watchdog::internal::PerStateIoOveruseThreshold>&
+ categorySpecific,
+ const std::vector<android::automotive::watchdog::internal::IoOveruseAlertThreshold>&
+ systemWide);
+
+PerStateBytes toPerStateBytes(const int64_t fgBytes, const int64_t bgBytes,
+ const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+ const std::string& name, const PerStateBytes& perStateBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+ const std::string& name, const int64_t fgBytes, const int64_t bgBytes,
+ const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+ const android::automotive::watchdog::internal::ComponentType type,
+ const PerStateBytes& perStateBytes);
+
+android::automotive::watchdog::internal::PerStateIoOveruseThreshold toPerStateIoOveruseThreshold(
+ const android::automotive::watchdog::internal::ComponentType type, const int64_t fgBytes,
+ const int64_t bgBytes, const int64_t garageModeBytes);
+
+android::automotive::watchdog::internal::PackageMetadata toPackageMetadata(
+ std::string packageName,
+ android::automotive::watchdog::internal::ApplicationCategoryType type);
+
+android::automotive::watchdog::internal::IoOveruseAlertThreshold toIoOveruseAlertThreshold(
+ const int64_t durationInSeconds, const int64_t writtenBytesPerSecond);
+
+testing::Matcher<const android::automotive::watchdog::internal::ResourceOveruseConfiguration>
+ResourceOveruseConfigurationMatcher(
+ const android::automotive::watchdog::internal::ResourceOveruseConfiguration& config);
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
+
+#endif // CPP_WATCHDOG_SERVER_TESTS_OVERUSECONFIGURATIONTESTUTILS_H_
diff --git a/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
new file mode 100644
index 0000000..2595c2b
--- /dev/null
+++ b/cpp/watchdog/server/tests/OveruseConfigurationXmlHelperTest.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "OveruseConfigurationTestUtils.h"
+#include "OveruseConfigurationXmlHelper.h"
+
+#include <android-base/file.h>
+#include <android-base/result.h>
+#include <android/automotive/watchdog/internal/ApplicationCategoryType.h>
+#include <android/automotive/watchdog/internal/ComponentType.h>
+#include <gmock/gmock.h>
+
+namespace android {
+namespace automotive {
+namespace watchdog {
+
+using ::android::automotive::watchdog::internal::ApplicationCategoryType;
+using ::android::automotive::watchdog::internal::ComponentType;
+using ::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
+
+namespace {
+
+constexpr const char* kTestDataDir = "/tests/data/";
+
+constexpr const char* kValidSystemConfiguration = "valid_overuse_system_configuration.xml";
+constexpr const char* kValidVendorConfiguration = "valid_overuse_vendor_configuration.xml";
+constexpr const char* kValidThirdPartyConfiguration = "valid_overuse_third_party_configuration.xml";
+
+const std::vector<const char*> kInvalidOveruseConfigurations =
+ {"duplicate_component_io_thresholds_overuse_configuration.xml",
+ "duplicate_component_type_overuse_configuration.xml",
+ "duplicate_io_config_overuse_configuration.xml",
+ "incomplete_app_category_io_thresholds_overuse_configuration.xml",
+ "incomplete_component_io_thresholds_overuse_configuration.xml",
+ "incomplete_pkg_io_thresholds_overuse_configuration.xml",
+ "incomplete_systemwide_io_thresholds_overuse_configuration.xml",
+ "invalid_component_type_overuse_configuration.xml",
+ "invalid_param_systemwide_io_thresholds_overuse_configuration.xml",
+ "invalid_state_app_category_io_thresholds_overuse_configuration.xml",
+ "invalid_state_component_io_thresholds_overuse_configuration.xml",
+ "invalid_state_pkg_io_thresholds_overuse_configuration.xml",
+ "invalid_type_app_category_mapping_overuse_configuration.xml",
+ "missing_component_io_thresholds_overuse_configuration.xml",
+ "missing_io_config_overuse_configuration.xml",
+ "missing_pkg_name_app_category_mapping_overuse_configuration.xml",
+ "missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml",
+ "missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml",
+ "missing_threshold_app_category_io_thresholds_overuse_configuration.xml",
+ "missing_threshold_component_io_thresholds_overuse_configuration.xml",
+ "missing_threshold_pkg_io_thresholds_overuse_configuration.xml",
+ "missing_threshold_systemwide_io_thresholds_overuse_configuration.xml"};
+
+std::string getTestFilePath(const char* filename) {
+ static std::string baseDir = android::base::GetExecutableDirectory();
+ return baseDir + kTestDataDir + filename;
+}
+
+} // namespace
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidSystemConfiguration) {
+ auto ioConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::SYSTEM, 300, 150, 500),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("system.package.C", 400, 100, 200),
+ toPerStateIoOveruseThreshold("system.package.D", 1024, 500, 2048)},
+ /*categorySpecific=*/{},
+ /*systemWide=*/{toIoOveruseAlertThreshold(10, 200), toIoOveruseAlertThreshold(5, 50)});
+ ResourceOveruseConfiguration expected =
+ constructResourceOveruseConfig(ComponentType::SYSTEM,
+ /*safeToKill=*/{"system.package.A", "system.package.B"},
+ /*vendorPrefixes=*/{},
+ /*packageMetadata=*/
+ {toPackageMetadata("system.package.A",
+ ApplicationCategoryType::MEDIA),
+ toPackageMetadata("system.package.B",
+ ApplicationCategoryType::MAPS)},
+ ioConfig);
+ auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+ getTestFilePath(kValidSystemConfiguration).c_str());
+ ASSERT_RESULT_OK(actual);
+ EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+ << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidVendorConfiguration) {
+ auto ioConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::VENDOR, 1024, 512, 3072),
+ /*packageSpecific=*/
+ {toPerStateIoOveruseThreshold("com.vendor.package.C", 400, 100, 200),
+ toPerStateIoOveruseThreshold("com.vendor.package.D", 1024, 500, 2048)},
+ /*categorySpecific=*/
+ {toPerStateIoOveruseThreshold("MAPS", 800, 900, 2048),
+ toPerStateIoOveruseThreshold("MEDIA", 600, 700, 1024)},
+ /*systemWide=*/{});
+ ResourceOveruseConfiguration expected =
+ constructResourceOveruseConfig(ComponentType::VENDOR,
+ /*safeToKill=*/
+ {"com.vendor.package.A", "com.vendor.package.B"},
+ /*vendorPrefixes=*/{"com.vendor.package"},
+ /*packageMetadata=*/
+ {toPackageMetadata("com.vendor.package.A",
+ ApplicationCategoryType::MEDIA),
+ toPackageMetadata("com.vendor.package.B",
+ ApplicationCategoryType::MAPS),
+ toPackageMetadata("com.third.party.package.C",
+ ApplicationCategoryType::MEDIA),
+ toPackageMetadata("system.package.D",
+ ApplicationCategoryType::MAPS)},
+ ioConfig);
+ auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+ getTestFilePath(kValidVendorConfiguration).c_str());
+ ASSERT_RESULT_OK(actual);
+ EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+ << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestValidThirdPartyConfiguration) {
+ auto ioConfig = constructIoOveruseConfig(
+ /*componentLevel=*/toPerStateIoOveruseThreshold(ComponentType::THIRD_PARTY, 300, 150,
+ 500),
+ /*packageSpecific=*/{},
+ /*categorySpecific=*/{},
+ /*systemWide=*/{});
+ ResourceOveruseConfiguration expected =
+ constructResourceOveruseConfig(ComponentType::THIRD_PARTY,
+ /*safeToKill=*/{},
+ /*vendorPrefixes=*/{},
+ /*packageMetadata=*/{}, ioConfig);
+ auto actual = OveruseConfigurationXmlHelper::parseXmlFile(
+ getTestFilePath(kValidThirdPartyConfiguration).c_str());
+ ASSERT_RESULT_OK(actual);
+ EXPECT_THAT(*actual, ResourceOveruseConfigurationMatcher(expected))
+ << "Expected: " << expected.toString() << "\nActual: " << actual->toString();
+}
+
+TEST(OveruseConfigurationXmlHelperTest, TestInvalidOveruseConfigurations) {
+ for (const auto& filename : kInvalidOveruseConfigurations) {
+ ASSERT_FALSE(
+ OveruseConfigurationXmlHelper::parseXmlFile(getTestFilePath(filename).c_str()).ok())
+ << "Must return error on parsing '" << filename << "'";
+ }
+}
+
+} // namespace watchdog
+} // namespace automotive
+} // namespace android
diff --git a/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..9db8129
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml
new file mode 100644
index 0000000..9b04e11
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_component_type_overuse_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+ <componentType> THIRD_PARTY </componentType>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml b/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml
new file mode 100644
index 0000000..5a1b801
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/duplicate_io_config_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..3de9084
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <appCategorySpecificThresholds>
+ <appCategoryThreshold id="MEDIA">
+ <state id="foreground_mode"> 600 </state>
+ <state id="background_mode"> 700 </state>
+ </appCategoryThreshold>
+ </appCategorySpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..59f5f2c
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..abd372c
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <packageSpecificThresholds id="system.package.C">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"> 100 </state>
+ </packageSpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..8233207
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/incomplete_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <systemWideThresholds>
+ <param id="written_bytes_per_second"> 200 </param>
+ </systemWideThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml
new file mode 100644
index 0000000..06f351f
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_component_type_overuse_configuration.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> RANDOM </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..77f523e
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_param_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <systemWideThresholds>
+ <param id="duration_seconds"> 10 </param>
+ <param id="written_bytes_per_second"> 200 </param>
+ <param id="random_param"> 200 </param>
+ </systemWideThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..c2f6d6a
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <appCategorySpecificThresholds>
+ <appCategoryThreshold id="MEDIA">
+ <state id="foreground_mode"> 600 </state>
+ <state id="background_mode"> 700 </state>
+ <state id="garage_mode"> 1024 </state>
+ <state id="random_mode"> 1024 </state>
+ </appCategoryThreshold>
+ </appCategorySpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..a86cf54
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ <state id="random_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..377b2d7
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_state_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <packageSpecificThresholds id="system.package.C">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"> 100 </state>
+ <state id="garage_mode"> 500 </state>
+ <state id="random_mode"> 500 </state>
+ </packageSpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml b/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml
new file mode 100644
index 0000000..412c6d1
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/invalid_type_app_category_mapping_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <packagesToAppCategoryTypes>
+ <packageAppCategory type="OTHERS"> system.package.A </packageAppCategory>
+ <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+ </packagesToAppCategoryTypes>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..4fe5fd3
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration/>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml
new file mode 100644
index 0000000..0d286cf
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_io_config_overuse_configuration.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml
new file mode 100644
index 0000000..10b5019
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_app_category_mapping_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <packagesToAppCategoryTypes>
+ <packageAppCategory type="MEDIA"> </packageAppCategory>
+ <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+ </packagesToAppCategoryTypes>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..554f385
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <packageSpecificThresholds id="">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"> 100 </state>
+ <state id="garage_mode"> 200 </state>
+ </packageSpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml
new file mode 100644
index 0000000..a6fdb1d
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_pkg_name_safe_to_kill_entry_overuse_configuration.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <safeToKillPackages>
+ <package/>
+ </safeToKillPackages>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..7c264ef
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_app_category_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <appCategorySpecificThresholds>
+ <appCategoryThreshold id="MEDIA">
+ <state id="foreground_mode"/>
+ <state id="background_mode"> 700 </state>
+ <state id="garage_mode"> 500 </state>
+ </appCategoryThreshold>
+ </appCategorySpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..dfab251
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_component_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"/>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..8914406
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_pkg_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <packageSpecificThresholds id="system.package.C">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"/>
+ <state id="garage_mode"> 100 </state>
+ </packageSpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml b/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml
new file mode 100644
index 0000000..0341c06
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/missing_threshold_systemwide_io_thresholds_overuse_configuration.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <ioOveruseConfiguration>
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <systemWideThresholds>
+ <param id="duration_seconds"> 10 </param>
+ <param id="written_bytes_per_second"/>
+ </systemWideThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml
new file mode 100644
index 0000000..854abc7
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_system_configuration.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> SYSTEM </componentType>
+
+ <!-- List of safe to kill system packages. -->
+ <safeToKillPackages>
+ <package> system.package.A </package>
+ <package> system.package.B </package>
+ </safeToKillPackages>
+
+ <!-- List of unique package names to app category mappings. -->
+ <packagesToAppCategoryTypes>
+ <packageAppCategory type="MEDIA"> system.package.A </packageAppCategory>
+ <packageAppCategory type="MAPS"> system.package.B </packageAppCategory>
+ </packagesToAppCategoryTypes>
+
+ <ioOveruseConfiguration>
+ <!-- Thresholds in MiB for all system packages that don’t have package specific thresholds. -->
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+
+ <!-- Package specific thresholds. -->
+ <packageSpecificThresholds id="system.package.C">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"> 100 </state>
+ <state id="garage_mode"> 200 </state>
+ </packageSpecificThresholds>
+
+ <packageSpecificThresholds id="system.package.D">
+ <state id="foreground_mode"> 1024 </state>
+ <state id="background_mode"> 500 </state>
+ <state id="garage_mode"> 2048 </state>
+ </packageSpecificThresholds>
+
+ <!-- List of system-wide disk I/O overuse alert thresholds. -->
+ <systemWideThresholds>
+ <param id="duration_seconds"> 10 </param>
+ <param id="written_bytes_per_second"> 200 </param>
+ </systemWideThresholds>
+
+ <systemWideThresholds>
+ <param id="duration_seconds"> 5 </param>
+ <param id="written_bytes_per_second"> 50 </param>
+ </systemWideThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml
new file mode 100644
index 0000000..b3bacb6
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_third_party_configuration.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> THIRD_PARTY </componentType>
+ <ioOveruseConfiguration>
+ <!-- Thresholds in MiB for all third-party packages. -->
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 300 </state>
+ <state id="background_mode"> 150 </state>
+ <state id="garage_mode"> 500 </state>
+ </componentLevelThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
\ No newline at end of file
diff --git a/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml b/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml
new file mode 100644
index 0000000..b7b4341
--- /dev/null
+++ b/cpp/watchdog/server/tests/data/valid_overuse_vendor_configuration.xml
@@ -0,0 +1,75 @@
+<?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.
+-->
+
+<resourceOveruseConfiguration version="1.0">
+ <componentType> VENDOR </componentType>
+
+ <!-- List of safe to kill system packages. -->
+ <safeToKillPackages>
+ <package> com.vendor.package.A </package>
+ <package> com.vendor.package.B </package>
+ </safeToKillPackages>
+
+ <!-- List of vendor package prefixes. -->
+ <vendorPackagePrefixes>
+ <packagePrefix> com.vendor.package </packagePrefix>
+ </vendorPackagePrefixes>
+
+ <!-- List of unique package names to app category mappings. -->
+ <packagesToAppCategoryTypes>
+ <packageAppCategory type="MEDIA"> com.vendor.package.A </packageAppCategory>
+ <packageAppCategory type="MAPS"> com.vendor.package.B </packageAppCategory>
+ <packageAppCategory type="MEDIA"> com.third.party.package.C </packageAppCategory>
+ <packageAppCategory type="MAPS"> system.package.D </packageAppCategory>
+ </packagesToAppCategoryTypes>
+
+ <ioOveruseConfiguration>
+ <!-- Thresholds in MiB for all vendor packages that don’t have package specific thresholds. -->
+ <componentLevelThresholds>
+ <state id="foreground_mode"> 1024 </state>
+ <state id="background_mode"> 512 </state>
+ <state id="garage_mode"> 3072 </state>
+ </componentLevelThresholds>
+
+ <!-- Package specific thresholds. -->
+ <packageSpecificThresholds id="com.vendor.package.C">
+ <state id="foreground_mode"> 400 </state>
+ <state id="background_mode"> 100 </state>
+ <state id="garage_mode"> 200 </state>
+ </packageSpecificThresholds>
+
+ <packageSpecificThresholds id="com.vendor.package.D">
+ <state id="foreground_mode"> 1024 </state>
+ <state id="background_mode"> 500 </state>
+ <state id="garage_mode"> 2048 </state>
+ </packageSpecificThresholds>
+
+ <!-- Application category specific thresholds. -->
+ <appCategorySpecificThresholds>
+ <appCategoryThreshold id="MEDIA">
+ <state id="foreground_mode"> 600 </state>
+ <state id="background_mode"> 700 </state>
+ <state id="garage_mode"> 1024 </state>
+ </appCategoryThreshold>
+
+ <appCategoryThreshold id="MAPS">
+ <state id="foreground_mode"> 800 </state>
+ <state id="background_mode"> 900 </state>
+ <state id="garage_mode"> 2048 </state>
+ </appCategoryThreshold>
+ </appCategorySpecificThresholds>
+ </ioOveruseConfiguration>
+</resourceOveruseConfiguration>
diff --git a/packages/CarDeveloperOptions/AndroidManifest.xml b/packages/CarDeveloperOptions/AndroidManifest.xml
index ddd97dc..6dbba33 100644
--- a/packages/CarDeveloperOptions/AndroidManifest.xml
+++ b/packages/CarDeveloperOptions/AndroidManifest.xml
@@ -21,8 +21,9 @@
package="com.android.car.developeroptions"
android:sharedUserId="android.uid.system">
- <application android:label="@string/settings_label"
- tools:node="merge">
+ <application android:label="@string/development_settings_title"
+ tools:node="merge"
+ tools:replace="android:label">
<activity
android:name=".CarDevelopmentSettingsDashboardActivity"
@@ -562,6 +563,15 @@
</activity>
<activity
+ android:name="com.android.settings.Settings$LockScreenSettingsActivity"
+ android:enabled="false"
+ android:exported="false"
+ tools:node="merge"
+ tools:replace="android:exported">
+ <intent-filter tools:node="removeAll"/>
+ </activity>
+
+ <activity
android:name="com.android.settings.SettingsLicenseActivity"
android:enabled="false"
android:exported="false"
diff --git a/service/res/values-bn/strings.xml b/service/res/values-bn/strings.xml
index 5b8c5e2..3e30d75 100644
--- a/service/res/values-bn/strings.xml
+++ b/service/res/values-bn/strings.xml
@@ -127,10 +127,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"গাড়ির ভেন্ডরের অনুমতি সম্পর্কে তথ্য অ্যাক্সেস করুন।"</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস দেখা"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইটের স্ট্যাটাস অ্যাক্সেস করা।"</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"গাড়ির সময় পর্বের তথ্য ব্যবহার করুন।"</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"গাড়ির এনক্রিপশন বাইন্ডিং সিড অ্যাক্সেস করুন।"</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"গাড়ির এক্সটিরিয়র বা বাইরের দিকের লাইট দেখা"</string>
diff --git a/service/res/values-gu/strings.xml b/service/res/values-gu/strings.xml
index 484ef9d..b587127 100644
--- a/service/res/values-gu/strings.xml
+++ b/service/res/values-gu/strings.xml
@@ -128,10 +128,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"કારના વિક્રેતાની પરવાનગી વિશેની માહિતીને ઍક્સેસ કરો."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"કારની બહારની લાઇટની સ્થિતિને વાંચો"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"કારની બહારની લાઇટની સ્થિતિને ઍક્સેસ કરો."</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"કારનો epoch સમય ઍક્સેસ કરો"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"કારનો epoch સમય ઍક્સેસ કરો."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"કારના એન્ક્રિપ્શન બાઇન્ડિંગ સીડને ઍક્સેસ કરો."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"કારની બહારની લાઇટ વિશે વાંચો"</string>
diff --git a/service/res/values-kn/strings.xml b/service/res/values-kn/strings.xml
index e0e339e..2feb952 100644
--- a/service/res/values-kn/strings.xml
+++ b/service/res/values-kn/strings.xml
@@ -127,10 +127,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"ಕಾರಿನ ಮಾರಾಟಗಾರರ ಅನುಮತಿ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್ಗಳ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್ಗಳ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"ಕಾರ್ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"ಕಾರ್ನ epoch ಸಮಯವನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"ಕಾರ್ನ ಎನ್ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"ಕಾರ್ನ ಎನ್ಕ್ರಿಪ್ಶನ್ ಬೈಡಿಂಗ್ ಸೀಡ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿ."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"ಕಾರಿನ ಹೊರಾಂಗಣ ಲೈಟ್ಗಳ ಮಾಹಿತಿಯನ್ನು ಓದಿ"</string>
diff --git a/service/res/values-mr/strings.xml b/service/res/values-mr/strings.xml
index d1b58b1..b93702f 100644
--- a/service/res/values-mr/strings.xml
+++ b/service/res/values-mr/strings.xml
@@ -127,10 +127,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"कारच्या विक्रेता परवानगी माहिती ॲक्सेस करा."</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"कारच्या बाहेरील लाइटची स्थिती वाचा"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"कारच्या बाहेरील लाइटची स्थिती अॅक्सेस करा."</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"कारचा कालावधी अॅक्सेस करू द्या"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"कारचा कालावधी अॅक्सेस करू द्या."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"कारचे एंक्रिप्शन बाइंडिंग सीड अॅक्सेस करा"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"कारचे एंक्रिप्शन बाइंडिंग सीड अॅक्सेस करा."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"कारच्या बाहेरच्या लाइटची स्थिती वाचा"</string>
diff --git a/service/res/values-or/strings.xml b/service/res/values-or/strings.xml
index c6754ac..0aad28e 100644
--- a/service/res/values-or/strings.xml
+++ b/service/res/values-or/strings.xml
@@ -127,10 +127,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"କାର୍\'ର ଭେଣ୍ଡର୍ ଅନୁମତି ସୂୂଚନା ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"କାର୍\'ର ବାହାର ଲାଇଟ୍ଗୁଡ଼ିକର ଷ୍ଟେଟ୍କୁ ପଢ଼ିବ"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"କାର୍\'ର ବାହାର ଲାଇଟ୍ଗୁଡ଼ିକର ଷ୍ଟେଟ୍କୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"କାରର epoch ସମୟକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"କାରର ଏନକ୍ରିପସନ୍ ବାଇଣ୍ଡିଂ ସିଡକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ।"</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"କାର୍\'ର ବାହାର ଲାଇଟ୍ଗୁଡ଼ିକର ସ୍ଥିତିକୁ ପଢ଼ିବ"</string>
diff --git a/service/res/values-uk/strings.xml b/service/res/values-uk/strings.xml
index 457df66..6f3cf6f 100644
--- a/service/res/values-uk/strings.xml
+++ b/service/res/values-uk/strings.xml
@@ -128,7 +128,7 @@
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"перегляд стану зовнішніх світлових приладів автомобіля"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"Керування зовнішніми світловими приладами автомобіля."</string>
<string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"доступ до часу UNIX автомобіля"</string>
- <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ до часу UNIX автомобіля"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"Доступ до часу UNIX автомобіля."</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"доступ до джерела шифрування автомобіля"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"Доступ до джерела шифрування автомобіля."</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"перегляд зовнішніх світлових приладів автомобіля"</string>
diff --git a/service/res/values-ur/strings.xml b/service/res/values-ur/strings.xml
index 3708846..c29597b 100644
--- a/service/res/values-ur/strings.xml
+++ b/service/res/values-ur/strings.xml
@@ -127,10 +127,8 @@
<string name="car_permission_desc_vendor_permission_info" msgid="8152113853528488398">"کار کے وینڈر کے اجازت کی معلومات تک رسائی حاصل کریں۔"</string>
<string name="car_permission_label_car_exterior_lights" msgid="541304469604902110">"کار کی بیرونی روشنیوں کی صورتحال کے بارے میں پڑھیں"</string>
<string name="car_permission_desc_car_exterior_lights" msgid="4038037584100849318">"کار کی بیرونی روشنیوں کی صورتحال تک رسائی حاصل کریں۔"</string>
- <!-- no translation found for car_permission_label_car_epoch_time (6303397910662625112) -->
- <skip />
- <!-- no translation found for car_permission_desc_car_epoch_time (398907082895238558) -->
- <skip />
+ <string name="car_permission_label_car_epoch_time" msgid="6303397910662625112">"کار کے epoch وقت تک رسائی حاصل کریں"</string>
+ <string name="car_permission_desc_car_epoch_time" msgid="398907082895238558">"کار کے epoch وقت تک رسائی حاصل کریں۔"</string>
<string name="car_permission_label_encryption_binding_seed" msgid="4652180636501144684">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں"</string>
<string name="car_permission_desc_encryption_binding_seed" msgid="6290944678417286024">"کار کی مرموز کاری واجب التعمیل سیڈ تک رسائی حاصل کریں۔"</string>
<string name="car_permission_label_control_car_exterior_lights" msgid="101357531386232141">"کار کی بیرونی روشنیوں کے بارے میں پڑھیں"</string>
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 9800e4d..7a8c9cb 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -238,6 +238,8 @@
PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_KEY,
android.Manifest.permission.INJECT_EVENTS);
+ USER_BUILD_COMMAND_TO_PERMISSION_MAP.put(COMMAND_INJECT_ROTARY,
+ android.Manifest.permission.INJECT_EVENTS);
}
private static final String PARAM_DAY_MODE = "day";
diff --git a/service/src/com/android/car/audio/CarAudioContext.java b/service/src/com/android/car/audio/CarAudioContext.java
index c93eca3..ecd8259 100644
--- a/service/src/com/android/car/audio/CarAudioContext.java
+++ b/service/src/com/android/car/audio/CarAudioContext.java
@@ -220,6 +220,9 @@
}
}
+ private CarAudioContext() {
+ }
+
/**
* Checks if the audio context is within the valid range from MUSIC to SYSTEM_SOUND
*/
diff --git a/service/src/com/android/car/audio/CarAudioUtils.java b/service/src/com/android/car/audio/CarAudioUtils.java
index 6724156..b787efb 100644
--- a/service/src/com/android/car/audio/CarAudioUtils.java
+++ b/service/src/com/android/car/audio/CarAudioUtils.java
@@ -16,7 +16,10 @@
package com.android.car.audio;
-class CarAudioUtils {
+final class CarAudioUtils {
+ private CarAudioUtils() {
+ }
+
static boolean hasExpired(long startTimeMs, long currentTimeMs, int timeoutMs) {
return (currentTimeMs - startTimeMs) > timeoutMs;
}
diff --git a/service/src/com/android/car/audio/CarAudioZonesValidator.java b/service/src/com/android/car/audio/CarAudioZonesValidator.java
index 4a74cd8..5fe495d 100644
--- a/service/src/com/android/car/audio/CarAudioZonesValidator.java
+++ b/service/src/com/android/car/audio/CarAudioZonesValidator.java
@@ -21,7 +21,10 @@
import java.util.HashSet;
import java.util.Set;
-class CarAudioZonesValidator {
+final class CarAudioZonesValidator {
+ private CarAudioZonesValidator() {
+ }
+
static void validate(SparseArray<CarAudioZone> carAudioZones) {
validateAtLeastOneZoneDefined(carAudioZones);
validateVolumeGroupsForEachZone(carAudioZones);
diff --git a/service/src/com/android/car/audio/CarDuckingUtils.java b/service/src/com/android/car/audio/CarDuckingUtils.java
index d86a5bc..f386d62 100644
--- a/service/src/com/android/car/audio/CarDuckingUtils.java
+++ b/service/src/com/android/car/audio/CarDuckingUtils.java
@@ -106,6 +106,9 @@
sContextsToDuck.append(ANNOUNCEMENT, new int[0]);
}
+ private CarDuckingUtils() {
+ }
+
static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
Set<Integer> uniqueUsages = new HashSet<>();
for (AudioFocusInfo focusInfo : focusHolders) {
diff --git a/service/src/com/android/car/audio/hal/AudioControlFactory.java b/service/src/com/android/car/audio/hal/AudioControlFactory.java
index 9f4b248..5f26372 100644
--- a/service/src/com/android/car/audio/hal/AudioControlFactory.java
+++ b/service/src/com/android/car/audio/hal/AudioControlFactory.java
@@ -27,6 +27,9 @@
public final class AudioControlFactory {
private static final String TAG = CarLog.tagFor(AudioControlFactory.class);
+ private AudioControlFactory() {
+ }
+
/**
* Generates {@link AudioControlWrapper} for interacting with IAudioControl HAL service. The HAL
* version priority is: Current AIDL, HIDL V2, HIDL V1. The wrapper will try to fetch the
diff --git a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
index 67c7584..b985407 100644
--- a/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
+++ b/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
@@ -202,6 +202,16 @@
}
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public void requestAudioFocus(String usage, int zoneId, int focusGain) {
@AttributeUsage int usageValue = AudioAttributes.xsdStringToUsage(usage);
mListener.requestAudioFocus(usageValue, zoneId, focusGain);
diff --git a/service/src/com/android/car/evs/CarEvsService.java b/service/src/com/android/car/evs/CarEvsService.java
index 416d3eb..764fb08 100644
--- a/service/src/com/android/car/evs/CarEvsService.java
+++ b/service/src/com/android/car/evs/CarEvsService.java
@@ -144,12 +144,16 @@
public boolean isRequestingToStartActivity() {
return mOn;
}
+
+ public String toString() {
+ return "ServiceType = " + mServiceType + ", mOn = " + mOn +
+ ", Timestamp = " + mTimestamp;
+ }
}
private final Context mContext;
private final EvsHalService mEvsHalService;
private final CarPropertyService mPropertyService;
- // Shouldn't acquire mStateLock holding mLock.
private final Object mLock = new Object();
// This handler is to monitor the client sends a video stream request within a given time
@@ -223,18 +227,16 @@
// CarEvsService state machine implementation to handle all state transitions.
private final class StateMachine {
- private Object mStateLock = new Object();
-
// Current state
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private int mState = SERVICE_STATE_UNAVAILABLE;
// Current service type
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private int mServiceType = CarEvsManager.SERVICE_TYPE_REARVIEW;
// Priority of a last service request
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private int mLastRequestPriority = REQUEST_PRIORITY_LOW;
public @CarEvsError int execute(int priority, int destination) {
@@ -253,17 +255,18 @@
public @CarEvsError int execute(int priority, int destination, int service, IBinder token,
ICarEvsStreamCallback callback) {
- if (mState == destination && destination != SERVICE_STATE_REQUESTED) {
- // Nothing to do
- return ERROR_NONE;
- }
+ int result = ERROR_NONE;
+ synchronized (mLock) {
+ // TODO(b/188970686): Reduce this lock duration.
+ if (mState == destination && destination != SERVICE_STATE_REQUESTED) {
+ // Nothing to do
+ return ERROR_NONE;
+ }
- int previousState = mState;
- int result;
- Slog.d(TAG_EVS, "Transition requested: " + toString(previousState) +
- " -> " + toString(destination));
+ int previousState = mState;
+ Slog.d(TAG_EVS, "Transition requested: " + toString(previousState) +
+ " -> " + toString(destination));
- synchronized (mStateLock) {
switch (destination) {
case SERVICE_STATE_UNAVAILABLE:
result = handleTransitionToUnavailableLocked();
@@ -296,24 +299,24 @@
}
public @CarEvsServiceState int getState() {
- synchronized (mStateLock) {
+ synchronized (mLock) {
return mState;
}
}
public @CarEvsServiceType int getServiceType() {
- synchronized (mStateLock) {
+ synchronized (mLock) {
return mServiceType;
}
}
public CarEvsStatus getStateAndServiceType() {
- synchronized (mStateLock) {
+ synchronized (mLock) {
return new CarEvsStatus(mServiceType, mState);
}
}
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private @CarEvsError int handleTransitionToUnavailableLocked() {
// This transition happens only when CarEvsService loses the active connection to the
// Extended View System service.
@@ -332,7 +335,7 @@
return ERROR_NONE;
}
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private @CarEvsError int handleTransitionToInactiveLocked(int priority, int service,
ICarEvsStreamCallback callback) {
@@ -383,7 +386,7 @@
return ERROR_NONE;
}
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private @CarEvsError int handleTransitionToRequestedLocked(int priority, int service) {
switch (mState) {
case SERVICE_STATE_UNAVAILABLE:
@@ -440,7 +443,7 @@
return ERROR_NONE;
}
- @GuardedBy("mStateLock")
+ @GuardedBy("mLock")
private @CarEvsError int handleTransitionToActiveLocked(int priority, int service,
IBinder token, ICarEvsStreamCallback callback) {
@@ -504,6 +507,10 @@
return "UNKNOWN";
}
}
+
+ public String toString() {
+ return toString(mState);
+ }
}
private final StateMachine mStateEngine = new StateMachine();
@@ -700,14 +707,15 @@
@Override
public void dump(IndentingPrintWriter writer) {
writer.println("*CarEvsService*");
- writer.printf("%s to HAL service",
+ writer.printf("Current state = %s\n", mStateEngine);
+ writer.printf("%s to HAL service\n",
mNativeEvsServiceObj == 0 ? "Not connected" : "Connected");
- writer.printf("%d stream listeners subscribed.",
+ writer.printf("%d stream listeners subscribed.\n",
mStreamCallbacks.getRegisteredCallbackCount());
- writer.printf("%d service listeners subscribed.",
+ writer.printf("%d service listeners subscribed.\n",
mStatusListeners.getRegisteredCallbackCount());
-
- // TODO(b/177923530): Dump more status information
+ writer.printf("Last HAL event = %s\n", mLastEvsHalEvent);
+ writer.printf("Current session token = %s\n", mSessionToken);
}
/**
diff --git a/service/src/com/android/car/hal/EvsHalService.java b/service/src/com/android/car/hal/EvsHalService.java
index f0228b9..011c6d8 100644
--- a/service/src/com/android/car/hal/EvsHalService.java
+++ b/service/src/com/android/car/hal/EvsHalService.java
@@ -190,7 +190,7 @@
@Override
public void dump(PrintWriter writer) {
- writer.println("*EVS HAL*");
+ writer.println("*EVSHALSERVICE*");
writer.printf("Use EVS_SERVICE_REQUEST: %b\n", isEvsServiceRequestSupported());
}
}
diff --git a/service/src/com/android/car/power/SilentModeHandler.java b/service/src/com/android/car/power/SilentModeHandler.java
index d64a070..11d6c8c 100644
--- a/service/src/com/android/car/power/SilentModeHandler.java
+++ b/service/src/com/android/car/power/SilentModeHandler.java
@@ -105,11 +105,14 @@
void init() {
boolean forcedMode;
+ boolean silentMode;
synchronized (mLock) {
forcedMode = mForcedMode;
+ silentMode = mSilentModeByHwState;
}
if (forcedMode) {
- updateKernelSilentMode(mSilentModeByHwState);
+ updateKernelSilentMode(silentMode);
+ mService.notifySilentModeChange(silentMode);
Slogf.i(TAG, "Now in forced mode: monitoring %s is disabled",
mHwStateMonitoringFileName);
} else {
diff --git a/service/src/com/android/car/telemetry/CarTelemetryService.java b/service/src/com/android/car/telemetry/CarTelemetryService.java
index d107cbd..695e25e 100644
--- a/service/src/com/android/car/telemetry/CarTelemetryService.java
+++ b/service/src/com/android/car/telemetry/CarTelemetryService.java
@@ -31,6 +31,7 @@
import android.util.Slog;
import com.android.car.CarServiceBase;
+import com.android.internal.annotations.GuardedBy;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -43,13 +44,18 @@
*/
public class CarTelemetryService extends ICarTelemetryService.Stub implements CarServiceBase {
+ // TODO(b/189340793): Rename Manifest to MetricsConfig
+
private static final boolean DEBUG = false;
private static final int DEFAULT_VERSION = 0;
private static final String TAG = CarTelemetryService.class.getSimpleName();
private final Context mContext;
+ @GuardedBy("mLock")
private final Map<String, Integer> mNameVersionMap = new HashMap<>();
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private ICarTelemetryServiceListener mListener;
public CarTelemetryService(Context context) {
@@ -79,10 +85,9 @@
// TODO(b/184890506): verify that only a hardcoded app can set the listener
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
- if (DEBUG) {
- Slog.d(TAG, "Setting the listener for car telemetry service");
+ synchronized (mLock) {
+ setListenerLocked(listener);
}
- mListener = listener;
}
/**
@@ -92,45 +97,25 @@
public void clearListener() {
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
- if (DEBUG) {
- Slog.d(TAG, "Clearing listener");
+ synchronized (mLock) {
+ clearListenerLocked();
}
- mListener = null;
}
/**
* Allows client to send telemetry manifests.
*
- * @param key the unique key to identify the manifest.
- * @param manifest the serialized bytes of a Manifest object.
+ * @param key the unique key to identify the manifest.
+ * @param config the serialized bytes of a Manifest object.
* @return {@link AddManifestError} the error code.
*/
@Override
- public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] manifest) {
+ public @AddManifestError int addManifest(@NonNull ManifestKey key, @NonNull byte[] config) {
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
- if (DEBUG) {
- Slog.d(TAG, "Adding manifest to car telemetry service");
+ synchronized (mLock) {
+ return addManifestLocked(key, config);
}
- int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
- if (currentVersion > key.getVersion()) {
- return ERROR_NEWER_MANIFEST_EXISTS;
- } else if (currentVersion == key.getVersion()) {
- return ERROR_SAME_MANIFEST_EXISTS;
- }
-
- TelemetryProto.Manifest parsedManifest;
- try {
- parsedManifest = TelemetryProto.Manifest.parseFrom(manifest);
- } catch (InvalidProtocolBufferException e) {
- Slog.e(TAG, "Failed to parse manifest.", e);
- return ERROR_PARSE_MANIFEST_FAILED;
- }
- mNameVersionMap.put(key.getName(), key.getVersion());
-
- // TODO(b/186047142): Store the manifest to disk
- // TODO(b/186047142): Send parsedManifest to a script manager or a queue
- return ERROR_NONE;
}
/**
@@ -140,15 +125,9 @@
public boolean removeManifest(@NonNull ManifestKey key) {
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
- if (DEBUG) {
- Slog.d(TAG, "Removing manifest from car telemetry service");
+ synchronized (mLock) {
+ return removeManifestLocked(key);
}
- Integer version = mNameVersionMap.remove(key.getName());
- if (version == null) {
- return false;
- }
- // TODO(b/186047142): Delete manifest from disk and remove it from queue
- return true;
}
/**
@@ -158,11 +137,9 @@
public void removeAllManifests() {
mContext.enforceCallingOrSelfPermission(
Car.PERMISSION_USE_CAR_TELEMETRY_SERVICE, "setListener");
- if (DEBUG) {
- Slog.d(TAG, "Removing all manifest from car telemetry service");
+ synchronized (mLock) {
+ removeAllManifestsLocked();
}
- mNameVersionMap.clear();
- // TODO(b/186047142): Delete all manifests from disk & queue
}
/**
@@ -204,4 +181,65 @@
Slog.d(TAG, "Flushing script execution errors");
}
}
+
+ @GuardedBy("mLock")
+ private void setListenerLocked(@NonNull ICarTelemetryServiceListener listener) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting the listener for car telemetry service");
+ }
+ mListener = listener;
+ }
+
+ @GuardedBy("mLock")
+ private void clearListenerLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "Clearing listener");
+ }
+ mListener = null;
+ }
+
+ @GuardedBy("mLock")
+ private @AddManifestError int addManifestLocked(ManifestKey key, byte[] configProto) {
+ if (DEBUG) {
+ Slog.d(TAG, "Adding MetricsConfig to car telemetry service");
+ }
+ int currentVersion = mNameVersionMap.getOrDefault(key.getName(), DEFAULT_VERSION);
+ if (currentVersion > key.getVersion()) {
+ return ERROR_NEWER_MANIFEST_EXISTS;
+ } else if (currentVersion == key.getVersion()) {
+ return ERROR_SAME_MANIFEST_EXISTS;
+ }
+
+ TelemetryProto.MetricsConfig metricsConfig;
+ try {
+ metricsConfig = TelemetryProto.MetricsConfig.parseFrom(configProto);
+ } catch (InvalidProtocolBufferException e) {
+ Slog.e(TAG, "Failed to parse MetricsConfig.", e);
+ return ERROR_PARSE_MANIFEST_FAILED;
+ }
+ mNameVersionMap.put(key.getName(), key.getVersion());
+
+ // TODO(b/186047142): Store the MetricsConfig to disk
+ // TODO(b/186047142): Send metricsConfig to a script manager or a queue
+ return ERROR_NONE;
+ }
+
+ @GuardedBy("mLock")
+ private boolean removeManifestLocked(@NonNull ManifestKey key) {
+ Integer version = mNameVersionMap.remove(key.getName());
+ if (version == null) {
+ return false;
+ }
+ // TODO(b/186047142): Delete manifest from disk and remove it from queue
+ return true;
+ }
+
+ @GuardedBy("mLock")
+ private void removeAllManifestsLocked() {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing all manifest from car telemetry service");
+ }
+ mNameVersionMap.clear();
+ // TODO(b/186047142): Delete all manifests from disk & queue
+ }
}
diff --git a/service/src/com/android/car/telemetry/Channel.java b/service/src/com/android/car/telemetry/Channel.java
new file mode 100644
index 0000000..100e227
--- /dev/null
+++ b/service/src/com/android/car/telemetry/Channel.java
@@ -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 com.android.car.telemetry;
+
+import android.os.Bundle;
+
+/**
+ * Buffers data passing from publishers to subscribers. There is one channel per script receptor.
+ *
+ * TODO(b/187525360, b/187743369): make it a class or create an impl class for this.
+ */
+public interface Channel {
+ /**
+ * Buffers the given data.
+ *
+ * TODO(b/189241508): Use ScriptExecutor supported data structure
+ */
+ void push(Bundle message);
+
+ /** Returns the publisher configuration for this channel. */
+ TelemetryProto.Publisher getPublisherConfig();
+
+ // TODO(b/187525360, b/187743369): Add other methods to check/get data from the channel.
+}
diff --git a/service/src/com/android/car/telemetry/LogFilter.java b/service/src/com/android/car/telemetry/LogFilter.java
deleted file mode 100644
index 8f72fe8..0000000
--- a/service/src/com/android/car/telemetry/LogFilter.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.telemetry;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
-import android.util.Log;
-
-import com.android.car.telemetry.TelemetryProto.LogListener;
-import com.android.car.telemetry.TelemetryProto.Manifest;
-
-import java.lang.annotation.Retention;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- * Encapsulates a filter that can be matched on log entries. Contains builder function to create
- * list of LogFilter given the loglistener.
- */
-public final class LogFilter {
-
- private static final String TAG = LogFilter.class.getSimpleName();
-
- /**
- * Types of filters to match against the logs. Different filter types will match in different
- * ways.
- */
- @Retention(SOURCE)
- @IntDef({FILTER_TAG, SUBSTRING})
- @interface FilterType {}
- static final int FILTER_TAG = 0;
- static final int SUBSTRING = 1;
-
- private final int mLogListenerIndex;
- private final @FilterType int mFilterType;
- private final String mFilter;
-
- LogFilter(int logListenerIndex, @FilterType int filterType, String filter) {
- this.mLogListenerIndex = logListenerIndex;
- this.mFilterType = filterType;
- if (filter == null) {
- throw new NullPointerException("Null filter");
- }
- this.mFilter = filter;
- }
-
- int getLogListenerIndex() {
- return mLogListenerIndex;
- }
-
- @LogFilter.FilterType int getFilterType() {
- return mFilterType;
- }
-
- String getFilter() {
- return mFilter;
- }
-
- /**
- * Creates a LogFilter instance.
- *
- * @param logListenerIndex the index of the logListener associated with the filter.
- * @param filterType the type of filter.
- * @param filter the value of the filter.
- * @return created LogFilter instance.
- */
- static LogFilter create(int logListenerIndex, @FilterType int filterType, String filter) {
- return new LogFilter(logListenerIndex, filterType, filter);
- }
-
- /**
- * Builds a List of {@link LogFilter} instances from {@link Manifest} and the logListener name.
- *
- * @param manifest {@link Manifest} file that contains list of logListeners.
- * @param logListenerName the name of the logListener as registered in the {@link Manifest}.
- * @return List of {@link LogFilter} instances.
- */
- static List<LogFilter> buildFilters(Manifest manifest, String logListenerName) {
- int logListenerIndex = getLogListenerIndexFromName(manifest, logListenerName);
- if (logListenerIndex == -1) {
- Log.w(TAG, "log listener with name " + logListenerName
- + " does not exist in manifest.");
- return Collections.unmodifiableList(new ArrayList<>());
- }
-
- List<LogFilter> result = new ArrayList<>();
- result.addAll(
- manifest.getLogListeners(logListenerIndex).getTagsList().stream()
- .map(tag -> LogFilter.create(logListenerIndex, FILTER_TAG, tag))
- .collect(Collectors.toList()));
- result.addAll(
- manifest.getLogListeners(logListenerIndex).getTypesList().stream()
- .map(LogFilter::typeToFilter)
- .filter(Optional::isPresent)
- .map(filter ->
- LogFilter.create(logListenerIndex, SUBSTRING, filter.get()))
- .collect(Collectors.toList()));
- return Collections.unmodifiableList(result);
- }
-
- /**
- * Gets the index of the {@link LogListener} in the manifest's list of logListeners.
- * Returns -1 if not found.
- *
- * @param manifest the {@link Manifest} that contains the definitions of the logListeners.
- * @param logListenerName name of the {@link LogListener} to get index for.
- * @return index of the logListener, -1 if not found.
- */
- static int getLogListenerIndexFromName(Manifest manifest, String logListenerName) {
- for (int i = 0; i < manifest.getLogListenersCount(); i++) {
- LogListener listener = manifest.getLogListeners(i);
- if (listener.getName().equals(logListenerName)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Converts log message filter {@link LogListener.Type} to corresponding filter string.
- *
- * @param type the filter {@link LogListener.Type}.
- * @return the corresponding filter string for the logListener type.
- */
- private static Optional<String> typeToFilter(LogListener.Type type) {
- switch (type) {
- case TYPE_UNSPECIFIED:
- return Optional.empty();
- case EXCEPTIONS:
- return Optional.of("Exception: ");
- }
- return Optional.empty();
- }
-
- /**
- * Matches in different ways against {@link LogcatReader.LogEntry} components depending on
- * filterType.
- *
- * @param entry the {@link LogcatReader.LogEntry} whose components will be matched against the
- * filters.
- * @return boolean denoting whether the filter can match the {@link LogcatReader.LogEntry}.
- */
- boolean matches(LogcatReader.LogEntry entry) {
- switch (getFilterType()) {
- case FILTER_TAG:
- return entry.mTag.equals(getFilter());
- case SUBSTRING:
- return entry.mMessage.contains(getFilter());
- }
- return false;
- }
-
- @Override
- public String toString() {
- return "LogFilter{"
- + "mLogListenerIndex=" + mLogListenerIndex + ", "
- + "mFilterType=" + mFilterType + ", "
- + "mFilter=" + mFilter
- + "}";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof LogFilter) {
- LogFilter that = (LogFilter) o;
- return this.mLogListenerIndex == that.getLogListenerIndex()
- && this.mFilterType == that.getFilterType()
- && this.mFilter.equals(that.getFilter());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int hash = 1;
- hash *= 1000003;
- hash ^= mLogListenerIndex;
- hash *= 1000003;
- hash ^= Integer.hashCode(mFilterType);
- hash *= 1000003;
- hash ^= mFilter.hashCode();
- return hash;
- }
-}
-
diff --git a/service/src/com/android/car/telemetry/LogcatReader.java b/service/src/com/android/car/telemetry/LogcatReader.java
deleted file mode 100644
index a83a72e..0000000
--- a/service/src/com/android/car/telemetry/LogcatReader.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.telemetry;
-
-import android.annotation.Nullable;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.ObjIntConsumer;
-import java.util.function.Supplier;
-
-/**
- * Reads Android logs while there are log listeners registered to it and sends the event through the
- * mLogEventConsumer.
- */
-public class LogcatReader {
- private static final String TAG = LogcatReader.class.getSimpleName();
-
- // TODO(b/180515554). Find a proper place for LOG_* constants.
- // They will be used in ScriptExecutor as well.
- /** The value of key to retrieve log seconds since epoch time from bundle. */
- private static final String LOG_SEC_KEY = "log.sec";
-
- /** The value of key to retrieve log nanoseconds from bundle. */
- private static final String LOG_NSEC_KEY = "log.nsec";
-
- /** The value of key to retrieve log tag from bundle. */
- private static final String LOG_TAG_KEY = "log.tag";
-
- /** The value of key to retrieve log message from bundle. */
- private static final String LOG_MESSAGE_KEY = "log.message";
-
- // Defined in system/core/liblog/include/log/log_read.h
- private static final int LOGGER_ENTRY_MAX_LEN = 5 * 1024;
-
- // The entry sizes differ in Android 10. See
- // https://cs.android.com/android/platform/superproject/+/android-10.0.0_r30:system/core/liblog/include/log/log_read.h
- public static final int ENTRY_V1_SIZE = 20;
- public static final int ENTRY_V2_V3_SIZE = 24;
- public static final int ENTRY_V4_SIZE = 28;
-
- private final AtomicBoolean mRunning = new AtomicBoolean(false);
-
- private final ObjIntConsumer<Bundle> mLogEventConsumer;
- private final Supplier<LocalSocket> mLocalSocketSupplier;
- private final Executor mExecutor;
-
- private final HashSet<LogFilter> mLogFilters = new HashSet<>();
-
- private synchronized boolean logFiltersEmpty() {
- return mLogFilters.isEmpty();
- }
-
- /**
- * Replicates {@code struct log_msg} from system/core/liblog/include/log/log_read.h and {@code
- * struct AndroidLogEntry} from system/core/liblog/include/log/logprint.h.
- */
- static class LogEntry {
- long mTvSec; // seconds since Epoch
- long mTvNSec; // nanoseconds
- int mPid; // generating process's pid
- long mTid; // generating process's tid
- long mUid; // generating process's uid
- int mPriority; // log priority, e.g. {@link Log#INFO}.
- String mTag;
- String mMessage;
-
- /**
- * Parses raw bytes received from {@code logd}.
- *
- * @param data raw bytes
- * @param readSize number of bytes received from logd.
- */
- @Nullable
- static LogEntry parse(byte[] data, int readSize) {
- // Parsing log_msg struct defined in system/core/liblog/include/log/log_read.h.
- // Only first headerSize is used to create LogEntry. Following message messageSize bytes
- // define log message.
- ByteBuffer dataBytes = ByteBuffer.wrap(data);
- dataBytes.order(ByteOrder.LITTLE_ENDIAN);
- int messageSize = dataBytes.getShort();
- int headerSize = dataBytes.getShort();
- if (readSize < messageSize + headerSize) {
- Log.w(
- TAG, "Invalid log message size "
- + (messageSize + headerSize)
- + ", received only "
- + readSize);
- return null;
- }
- LogEntry entry = new LogEntry();
- entry.mPid = dataBytes.getInt();
- entry.mTid = dataBytes.getInt();
- entry.mTvSec = dataBytes.getInt();
- entry.mTvNSec = dataBytes.getInt();
- if (headerSize >= ENTRY_V2_V3_SIZE) {
- dataBytes.position(dataBytes.position() + 4); // lid is not used here.
- }
- if (headerSize >= ENTRY_V4_SIZE) {
- entry.mUid = dataBytes.getInt();
- }
-
- // Parsing log message.
- // See android_log_processLogBuffer() in system/core/liblog/logprint.cpp for details.
- // message format: <priority:1><tag:N>\0<message:N>\0
- // TODO(b/180516393): improve message parsing that were not transferred
- // from the cpp above. Also verify this mechanism is ok from selinux perspective.
-
- if (messageSize < 3) {
- Log.w(TAG, "Log message is too small, size=" + messageSize);
- return null;
- }
- if (headerSize != dataBytes.position()) {
- Log.w(TAG, "Invalid header size " + headerSize + ", expected "
- + dataBytes.position());
- return null;
- }
- int msgStart = -1;
- int msgEnd = -1;
- for (int i = 1; i < messageSize; i++) {
- if (data[headerSize + i] == 0) {
- if (msgStart == -1) {
- msgStart = i + 1 + headerSize;
- } else {
- msgEnd = i + headerSize;
- break;
- }
- }
- }
- if (msgStart == -1) {
- Log.w(TAG, "Invalid log message");
- return null;
- }
- if (msgEnd == -1) {
- msgEnd = Math.max(msgStart, messageSize - 1);
- }
- entry.mPriority = data[headerSize];
- entry.mTag =
- new String(data, headerSize + 1, msgStart - headerSize - 2,
- StandardCharsets.US_ASCII);
- entry.mMessage =
- new String(data, msgStart, msgEnd - msgStart, StandardCharsets.US_ASCII);
- return entry;
- }
- }
-
- /**
- * Constructs {@link LogcatReader}.
- *
- * @param logEventConsumer a consumer that's called when a filter matches a log.
- * @param localSocketSupplier a supplier for LocalSocket to connect logd.
- * @param executor an {@link Executor} to run the LogcatReader instance.
- */
- public LogcatReader(
- ObjIntConsumer<Bundle> logEventConsumer,
- Supplier<LocalSocket> localSocketSupplier,
- Executor executor) {
- this.mLogEventConsumer = logEventConsumer;
- this.mLocalSocketSupplier = localSocketSupplier;
- this.mExecutor = executor;
- }
-
- /** Runs {@link LogcatReader}. */
- private void run() {
- Log.d(TAG, "Running LogcatReader");
-
- // Under the hood, logcat receives logs from logd, to remove the middleman, LogcatReader
- // doesn't run logcat, but directly connects to logd socket and parses raw logs.
- try (LocalSocket socket = mLocalSocketSupplier.get()) {
- // Connect to /dev/socket/logdr
- socket.connect(new LocalSocketAddress("logdr", LocalSocketAddress.Namespace.RESERVED));
- try (OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
- InputStream reader = socket.getInputStream()) {
- // Ask for streaming log and set tail=1 to get only new logs.
- // See system/core/liblog/logd_reader.cpp for example on how to interact with logdr.
- writer.write("stream tail=1");
- writer.flush();
- Log.d(TAG, "Sent request to logd and awaiting for logs");
-
- byte[] data = new byte[LOGGER_ENTRY_MAX_LEN + 1];
- while (!logFiltersEmpty()) {
- int n = reader.read(data, 0, LOGGER_ENTRY_MAX_LEN);
- if (n == -1) {
- Log.e(TAG, "Disconnected from logd");
- return;
- }
- LogEntry entry = LogEntry.parse(data, n);
- if (entry == null) {
- continue;
- }
-
- // Ignore the logs from the telemetry service. This
- // makes sure a recursive log storm does not happen - i.e. app produces a log
- // which in turn executes a code path that produces another log.
- if (entry.mUid == Process.myUid()) {
- continue;
- }
- // Check if it's running before processing the logs, because by the time we get
- // here ScriptExecutor might get disconnected.
- if (!mRunning.get()) {
- Log.d(TAG, "Not running anymore, exiting.");
- return;
- }
- // Keep track of which logListener an event for this entry has been sent,
- // so that the same entry isn't sent multiple times for the same logListener
- // if its multiple filters match.
- HashSet<Integer> sentLogListenerIndices = new HashSet<>();
- for (LogFilter filter : mLogFilters) {
- if (!sentLogListenerIndices.contains(filter.getLogListenerIndex())
- && filter.matches(entry)) {
- sentLogListenerIndices.add(filter.getLogListenerIndex());
- sendLogEvent(filter.getLogListenerIndex(), entry);
- }
- }
- }
- Log.d(TAG, "Log filters are empty, exiting.");
- }
- } catch (IOException e) {
- Log.e(TAG, "Failed to connect to logd", e);
- } finally {
- mRunning.set(false);
- }
- }
-
- /**
- * Sends the log event to the through the mLogEventConsumer.
- *
- * @param logListenerIndex the index of the logListener, whose function will receive the log
- * event.
- * @param entry the LogEntry instance to be bundled up and sent as event.
- */
- private void sendLogEvent(int logListenerIndex, LogEntry entry) {
- Bundle event = new Bundle();
- event.putLong(LOG_SEC_KEY, entry.mTvSec);
- event.putLong(LOG_NSEC_KEY, entry.mTvNSec);
- event.putString(LOG_TAG_KEY, entry.mTag);
- event.putString(LOG_MESSAGE_KEY, entry.mMessage);
- mLogEventConsumer.accept(event, logListenerIndex);
- }
-
- /**
- * Subscribes the list of {@link LogFilter} instances.
- *
- * @param newLogFilters the list of new log filters to be added to mLogFilters.
- */
- synchronized void subscribeLogFilters(List<LogFilter> newLogFilters) {
- mLogFilters.addAll(newLogFilters);
- }
-
- /**
- * Unsubscribes all {@link LogFilter} associated with the logListenerIndex
- *
- * @param logListenerIndex the index of the logListener to unregister.
- */
- synchronized void unsubscribeLogListener(int logListenerIndex) {
- mLogFilters.removeIf(lf -> lf.getLogListenerIndex() == logListenerIndex);
- }
-
- /** Starts the run method in a new thread if logcatReader isn't running already. */
- void startAsyncIfNotStarted() {
- if (mRunning.compareAndSet(false, true)) {
- mExecutor.execute(this::run);
- }
- }
-
- /** Gracefully stops {@link LogcatReader}. */
- synchronized void stop() {
- mRunning.set(false);
- mLogFilters.clear();
- }
-
- /** Builds a {@link LocalSocket} to read from {@code logdr}. */
- static LocalSocket buildLocalSocket() {
- return new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
- }
-}
diff --git a/service/src/com/android/car/telemetry/README.md b/service/src/com/android/car/telemetry/README.md
new file mode 100644
index 0000000..a2aee72
--- /dev/null
+++ b/service/src/com/android/car/telemetry/README.md
@@ -0,0 +1,28 @@
+<!--
+ 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
+ -->
+
+# CarTelemetryService
+
+Source code for AAOS OEM Telemetry solution.
+
+
+## Enabling CarTelemetryService
+
+CarTelemetryService can be enabled with
+
+```
+adb shell cmd car_service enable-feature car_telemetry_service
+```
diff --git a/service/src/com/android/car/telemetry/databroker/DataBroker.java b/service/src/com/android/car/telemetry/databroker/DataBroker.java
new file mode 100644
index 0000000..4f96966
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBroker.java
@@ -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.
+ */
+
+package com.android.car.telemetry.databroker;
+
+import android.os.Bundle;
+
+import com.android.car.telemetry.TelemetryProto;
+
+import java.util.List;
+
+/** Interface for the data path. Handles data forwarding from publishers to subscribers */
+public interface DataBroker {
+
+ /**
+ * ScriptResultListener is the listener for script results.
+ */
+ public interface ScriptResultListener {
+ /**
+ * Notifies listener of script result.
+ *
+ * @param scriptResult the script result.
+ */
+ void onScriptResult(Bundle scriptResult);
+ }
+
+ /**
+ * Updates the set of publishers whose data can be consumed by subscribers.
+ *
+ * @param allowedPublishers the types publisher data source that can be consumed. The class is
+ * generated by Protobuf oneof fields.
+ * @see
+ * <a href="https://developers.google.com/protocol-buffers/docs/reference/java-generated#oneof-fields">Oneof
+ * Fields Generated Code</a>
+ */
+ void enablePublishers(List<TelemetryProto.Publisher.PublisherCase> allowedPublishers);
+
+ /**
+ * Adds an active {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} that is pending
+ * execution.
+ */
+ void addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+
+ /**
+ * Removes a {@link com.android.car.telemetry.TelemetryProto.MetricsConfig} and all its
+ * relevant subscriptions.
+ */
+ void removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig);
+}
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
new file mode 100644
index 0000000..ab449e8
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.databroker;
+
+import android.os.Bundle;
+
+import com.android.car.telemetry.TelemetryProto.MetricsConfig;
+import com.android.car.telemetry.TelemetryProto.Publisher.PublisherCase;
+
+import java.util.ArrayList;
+
+/**
+ * DataBrokerController instantiates the DataBroker and manages what Publishers
+ * it can read from based current system states and policies.
+ */
+public class DataBrokerController {
+
+ private MetricsConfig mMetricsConfig;
+ private final DataBroker mDataBroker;
+ private final ArrayList<PublisherCase> mAllowedPublishers = new ArrayList<>();
+
+ public DataBrokerController() {
+ mDataBroker = new DataBrokerImpl(this::onScriptResult);
+ mAllowedPublishers.add(PublisherCase.VEHICLE_PROPERTY);
+ mDataBroker.enablePublishers(mAllowedPublishers);
+ }
+
+ /**
+ * Listens to script result from {@link DataBroker}.
+ *
+ * @param scriptResult the script result.
+ */
+ public void onScriptResult(Bundle scriptResult) {
+ // TODO(b/187744195)
+ }
+
+ /**
+ * Listens to new {@link MetricsConfig}.
+ *
+ * @param metricsConfig the metrics config.
+ */
+ public void onNewMetricsConfig(MetricsConfig metricsConfig) {
+ mMetricsConfig = metricsConfig;
+ mDataBroker.addMetricsConfiguration(mMetricsConfig);
+ }
+}
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
new file mode 100644
index 0000000..ff12dc2
--- /dev/null
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -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.
+ */
+
+package com.android.car.telemetry.databroker;
+
+import com.android.car.telemetry.TelemetryProto;
+
+import java.util.List;
+
+/**
+ * Implementation of the data path component of CarTelemetryService. Forwards the published data
+ * from publishers to consumers subject to the Controller's decision.
+ */
+public class DataBrokerImpl implements DataBroker {
+
+ private final ScriptResultListener mScriptResultListener;
+
+ public DataBrokerImpl(ScriptResultListener scriptResultListener) {
+ mScriptResultListener = scriptResultListener;
+ }
+
+ @Override
+ public void enablePublishers(List<TelemetryProto.Publisher.PublisherCase> allowedPublishers) {
+ // TODO(b/187743369): implement
+ }
+
+ @Override
+ public void addMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig) {
+ // TODO(b/187743369): implement
+ }
+
+ @Override
+ public void removeMetricsConfiguration(TelemetryProto.MetricsConfig metricsConfig) {
+ // TODO(b/187743369): implement
+ }
+}
diff --git a/service/src/com/android/car/telemetry/proto/telemetry.proto b/service/src/com/android/car/telemetry/proto/telemetry.proto
index 422c4a2..5787d62 100644
--- a/service/src/com/android/car/telemetry/proto/telemetry.proto
+++ b/service/src/com/android/car/telemetry/proto/telemetry.proto
@@ -21,50 +21,35 @@
option java_package = "com.android.car.telemetry";
option java_outer_classname = "TelemetryProto";
-// A Tpk (Telemetry Package) manifest.
-// It contains a script and the rules how the script runs on devices.
-message Manifest {
+// A metrics configuration.
+//
+// The metrics configuration describes a metric that is collected from a device.
+// It includes a declarative part that configures the metric and the data publisher
+// and a data handler to process the data and create a statistic.
+// The latter is written in Lua language.
+message MetricsConfig {
// Required.
- // Name of the Tpk, used to distinguish TPKs.
+ // The name of the configuration. Must be unique within a device.
// Only alphanumeric and _ characters are allowed. Minimum length is 3 chars.
optional string name = 1;
// Required.
- // A script that is executed in devices. Must contain all the functions
- // defined in the listeners below.
- optional string script = 2;
+ // Version number of the configuration.
+ optional int32 version = 2;
// Required.
- // A unique version number of the Tpk, used to distinguish between Tpks of the
- // same name.
- optional int32 version = 3;
+ // A script that is executed in devices. Must contain all the handler functions
+ // defined in the listeners below.
+ // The script functions must be `pure` functions.
+ optional string script = 3;
- // Telemetry service subscribes these listeners to vehicle property change events.
- // The functions must be present in the script.
- repeated PropertyChangeListener property_change_listeners = 4;
-
- // Telemetry service subscribes these listeners to Android log (logcat) events.
- // The functions must be present in the script.
- repeated LogListener log_listeners = 5;
-
- // Telemetry service subscribes these listeners to stats anomalies, such as
- // Alerts, Alarms, stats out-of-space anomaly and historical data anomaly.
- // The number of listener is limited to 10 by statsd.
- // The functions must be present in the script.
- repeated StatsListener stats_listeners = 6;
-
- // Dumpsys result listeners can be registered to retrieve dump report for
- // specified report types.
- // The functions must be present in the script.
- repeated DumpsysResultListener dumpsys_result_listeners = 7;
-
- // This timer executes functions when a specific event happens.
- // The functions must be present in the script.
- repeated Timer timers = 8;
+ // Required.
+ repeated Subscriber subscribers = 4;
}
-// A function that is executed when a vehicle property change events occur.
-message PropertyChangeListener {
+// Parameters for Vehicle Properties publisher.
+// See https://source.android.com/devices/automotive/vhal/properties
+message VehiclePropertyPublisher {
// Required.
// See packages/services/Car/car-lib/src/android/car/VehiclePropertyIds.java
optional int32 vehicle_property_id = 1;
@@ -73,197 +58,21 @@
// packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
// look for constants SENSOR_RATE_*;
optional float read_rate = 2;
-
- // Required.
- optional string function_name = 3;
}
-// A function that receives Android log (logcat) events. The log event is passed
-// as a string argument to the function.
-//
-// The LogListener will receive log events if the log event matches any of the
-// "types" or "tags".
-//
-// Please see ../README.md for details.
-//
-// Example:
-// function processException(log_event_line) ... end
-message LogListener {
- enum Type {
- // Default value.
- TYPE_UNSPECIFIED = 0;
-
- // Matches logged exceptions.
- EXCEPTIONS = 1;
+// Specifies data publisher and its parameters.
+message Publisher {
+ oneof publisher {
+ VehiclePropertyPublisher vehicle_property = 1;
}
-
- // Required.
- // Unique name of the logListener within the Tpk. Used to
- // subscribe/unsubscribe from log events.
- optional string name = 1;
-
- // Required.
- // Name of the function to be executed when the logs the logListener has a
- // match with its filters
- optional string function_name = 2;
-
- // Message types to listen to in LogCat.
- // At least one "types" or "tags" must be provided.
- repeated Type types = 3;
-
- // Tags to listen to in LogCat.
- // At least one "types" or "tags" must be provided.
- repeated string tags = 4;
}
-// A function that receives stats reports.
-//
-// LogProcessor App provides limited statsd support. Please see
-// logprocessor/README.md for details.
-//
-// Script function semantics:
-// -- Param report_list is a table with 1-1 mapping
-// to ConfigMetricsReportList.
-// -- Param extra_stats is a table { config_uid, config_key, ... } coming
-// -- from PendingIntent described in StatsManager#setBroadcastSubscriber().
-// function onStatdEvent(report_list, extra_stats) end
-message StatsListener {
- // Function to be called when the subscriptions below get triggered.
- optional string function_name = 1;
+// Specifies publisher with its parameters and the handler function that's invoked
+// when data is received. The format of the data depends on the Publisher.
+message Subscriber {
+ // Name of the script function that's invoked when this subscriber is triggered.
+ optional string handler = 1;
- // Serialized StatsdConfig defined in
- // AOSP/frameworks/base/cmds/statsd/src/statsd_config.proto
- // NOTE: Config ID and other generated IDs must be unique within this
- // statsd_config.
- optional bytes statsd_config = 2;
-
- // Subscribe the telemetry service to stats broadcast events: Alarms and Alerts.
- // Subscriptions must be defined in the statsd_config as
- // BroadcastSubscriberDetails.
- // NOTE: It must be unique within the statsd_config.
- optional int64 subscriber_id = 3;
-}
-
-// A function that receives Dumpsys reports.
-//
-// The DumpsysResultListener will receive dumpsys reports of the specified
-// DumpsysReportType
-message DumpsysResultListener {
- // Names of the system services that's allowed to run dumpsys on.
- enum SystemServiceName {
- UNSPECIFIED = 0;
-
- // Matches car service com.android.car.CarService.
- CAR_SERVICE = 1;
-
- // Matches package manager service
- // com.android.server.pm.PackageManagerService.
- PACKAGE = 2; //
- }
-
- // Required.
- // Unique name of the DumpsysResultListener within the Tpk.
- // Used to register the specific DumpsysResultListener needed.
- optional string name = 1;
-
- // Required.
- // Name of the function to be executed when a dumpsys report of the specified
- // system services are retrieved.
- optional string function_name = 2;
-
- // Required.
- // System service to run dumpsys for.
- optional SystemServiceName system_service_name = 3;
-
- // Extra arguments for dumpsys
- optional string arguments = 4;
-}
-
-// Runs a script function after some delay when an event happens.
-message Timer {
- enum TriggerType {
- TRIGGER_TYPE_UNSPECIFIED = 0;
-
- // When the device boots up.
- //
- // Note that when device wakes up from a deep sleep (suspend to ram), this
- // trigger doesn't work.
- //
- // It doesn't guarantee immediate activation of the timer right after the
- // boot, only after the system and the script is ready.
- // "initial_delay_millis" parameter denotes a delay from boot (not from
- // the script is initialized and ready).
- TRIGGER_TYPE_BOOT = 1;
- }
-
- // Required.
- // Name of the script function that will be executed.
- optional string function_name = 1;
-
- // Required.
- // An event trigger that activates this timer.
- optional TriggerType trigger_type = 2;
-
- // Required.
- // Delay after the trigger event before initial executing the function.
- //
- // Be careful putting long delays (>30 minutes), because the average
- // driving duration might be shorter than the delay, and the function
- // will be executed less frequently than desired amount.
- optional int64 initial_delay_millis = 3;
-
- // The max number of times the function will be periodically executed.
- // When this number of execution is reached, the timer will be stopped.
- // 0 means the timer is disabled.
- // -1 means the timer never stops.
- optional int32 max_count = 4;
-
- // Time between successive function executions if max_count >= 2.
- optional int64 period_millis = 5;
-}
-
-// A message that encapsulates different types of error or log metadata as
-// for informational and debugging purposes.
-//
-// When the app crashes or the system restarts, the timers will reset.
-message SecularTrendsLog {
- // Required.
- optional int64 timestamp = 1;
-
- enum LogType {
- // Default enum.
- UNSPECIFIED = 0;
-
- // Used when manifest is misconfigurated, such as missing required fields.
- MANIFEST_MISCONFIGURATION = 1;
-
- // Used when a Java service throws an exception.
- JAVA_EXCEPTION = 2;
-
- // Used when LogProc service failes to bind to sandbox service.
- SANDBOX_SERVICE_CONNECTION_FAILURE = 3;
-
- // Used when an error occurs in the native code.
- NATIVE_RUNTIME_ERROR = 4;
-
- // Used when an error occurs while executing the Lua script (such as
- // errors returned by lua_pcall)
- LUA_RUNTIME_ERROR = 5;
-
- // Used when a service that telemetry service depends on crashes or fails.
- DEPENDENT_SERVICE_FAILURE = 6;
- }
-
- // Required.
- // A type that indicates where the log is generated.
- optional LogType type = 2;
-
- // Required.
- // Human readable message explaining what’s wrong or how to fix it.
- optional string message = 3;
-
- // Optional.
- // If there is an exception, there will be stack trace. However this
- // information is not always available.
- optional string stack_trace = 4;
+ // Publisher and its parameters.
+ optional Publisher publisher = 2;
}
diff --git a/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java b/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java
new file mode 100644
index 0000000..a8795c2
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/LogcatPublisher.java
@@ -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 com.android.car.telemetry.publisher;
+
+import com.android.car.telemetry.Channel;
+
+/**
+ * Publisher for Android logs (adb logcat).
+ *
+ * TODO(b/187525360): Move the logic from LogcatReader here.
+ */
+public class LogcatPublisher implements Publisher {
+ /** See {@link Publisher#addChannel()} for details. */
+ public void addChannel(Channel channel) {
+ // TODO(b/187525360): implement
+ }
+
+ /** See {@link Publisher#removeChannel()} for details. */
+ public void removeChannel(Channel channel) {
+ // TODO(b/187525360): implement
+ }
+}
diff --git a/service/src/com/android/car/telemetry/publisher/Publisher.java b/service/src/com/android/car/telemetry/publisher/Publisher.java
new file mode 100644
index 0000000..5962711
--- /dev/null
+++ b/service/src/com/android/car/telemetry/publisher/Publisher.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry.publisher;
+
+import com.android.car.telemetry.Channel;
+
+/**
+ * Interface for publishers. It's implemented per data source, data is sent to {@link Channel}.
+ * Publisher stops itself when there are no channels.
+ *
+ * <p>Note that it doesn't map 1-1 to {@link TelemetryProto.Publisher} configuration. Single
+ * publisher instance can send data as several {@link TelemetryProto.Publisher} to subscribers.
+ */
+public interface Publisher {
+ /**
+ * Adds a channel to the publisher. Publisher will immediately start pushing
+ * data to the channel.
+ *
+ * @param channel a channel to publish data.
+ *
+ * @throws IllegalArgumentException if the channel was added before.
+ */
+ void addChannel(Channel channel);
+
+ /**
+ * Removes the channel from the publisher.
+ *
+ * @throws IllegalArgumentException if the channel was not found.
+ */
+ void removeChannel(Channel channel);
+}
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 52799cf..0e8e9f2 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -791,6 +791,8 @@
if (!isUserHalSupported()) {
fallbackToDefaultInitialUserBehavior(/* userLocales= */ null, replaceGuest);
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ_COMPLETE,
+ requestType);
return;
}
@@ -843,6 +845,8 @@
EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_RESP, status);
fallbackToDefaultInitialUserBehavior(/* user locale */ null, replaceGuest);
}
+ EventLog.writeEvent(EventLogTags.CAR_USER_SVC_INITIAL_USER_INFO_REQ_COMPLETE,
+ requestType);
});
}
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 8a83a9d..86858d4 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -137,6 +137,7 @@
*/
@Override
public void registerClient(ICarWatchdogServiceCallback client, int timeout) {
+ ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
mWatchdogProcessHandler.registerClient(client, timeout);
}
@@ -146,6 +147,7 @@
*/
@Override
public void unregisterClient(ICarWatchdogServiceCallback client) {
+ ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
mWatchdogProcessHandler.unregisterClient(client);
}
@@ -154,6 +156,7 @@
*/
@Override
public void tellClientAlive(ICarWatchdogServiceCallback client, int sessionId) {
+ ICarImpl.assertPermission(mContext, Car.PERMISSION_USE_CAR_WATCHDOG);
mWatchdogProcessHandler.tellClientAlive(client, sessionId);
}
diff --git a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
index feff1ef..8d15e0f 100644
--- a/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
+++ b/service/src/com/android/car/watchdog/WatchdogPerfHandler.java
@@ -87,6 +87,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
+import java.util.function.Consumer;
/**
* Handles system resource performance monitoring module.
@@ -112,11 +113,11 @@
private final List<PackageResourceOveruseAction> mOveruseActionsByUserPackage =
new ArrayList<>();
@GuardedBy("mLock")
- private final SparseArray<ResourceOveruseListenerInfo> mOveruseListenerInfosByUid =
+ private final SparseArray<ArrayList<ResourceOveruseListenerInfo>> mOveruseListenerInfosByUid =
new SparseArray<>();
@GuardedBy("mLock")
- private final SparseArray<ResourceOveruseListenerInfo> mOveruseSystemListenerInfosByUid =
- new SparseArray<>();
+ private final SparseArray<ArrayList<ResourceOveruseListenerInfo>>
+ mOveruseSystemListenerInfosByUid = new SparseArray<>();
/* Set of safe-to-kill system and vendor packages. */
@GuardedBy("mLock")
public final Set<String> mSafeToKillPackages = new ArraySet<>();
@@ -516,7 +517,7 @@
synchronized (mLock) {
checkAndHandleDateChangeLocked();
for (PackageIoOveruseStats stats : packageIoOveruseStats) {
- String packageName = packageNamesByUid.get(stats.uid, null);
+ String packageName = packageNamesByUid.get(stats.uid);
if (packageName == null) {
continue;
}
@@ -640,27 +641,19 @@
private void notifyResourceOveruseStatsLocked(int uid,
ResourceOveruseStats resourceOveruseStats) {
String packageName = resourceOveruseStats.getPackageName();
- ResourceOveruseListenerInfo listenerInfo = mOveruseListenerInfosByUid.get(uid, null);
- if (listenerInfo != null && (listenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) != 0) {
- try {
- listenerInfo.listener.onOveruse(resourceOveruseStats);
- } catch (RemoteException e) {
- Slogf.e(TAG, e, "Failed to notify listener(uid %d, package '%s') on resource "
- + "overuse", uid, resourceOveruseStats);
+ ArrayList<ResourceOveruseListenerInfo> listenerInfos = mOveruseListenerInfosByUid.get(uid);
+ if (listenerInfos != null) {
+ for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+ listenerInfo.notifyListener(FLAG_RESOURCE_OVERUSE_IO, uid, packageName,
+ resourceOveruseStats);
}
}
for (int i = 0; i < mOveruseSystemListenerInfosByUid.size(); ++i) {
- ResourceOveruseListenerInfo systemListenerInfo =
+ ArrayList<ResourceOveruseListenerInfo> systemListenerInfos =
mOveruseSystemListenerInfosByUid.valueAt(i);
- if ((systemListenerInfo.flag & FLAG_RESOURCE_OVERUSE_IO) == 0) {
- continue;
- }
- try {
- systemListenerInfo.listener.onOveruse(resourceOveruseStats);
- } catch (RemoteException e) {
- Slogf.e(TAG, e, "Failed to notify system listener(uid %d, pid: %d) of resource "
- + "overuse by package(uid %d, package '%s')", systemListenerInfo.uid,
- systemListenerInfo.pid, uid, packageName);
+ for (ResourceOveruseListenerInfo listenerInfo : systemListenerInfos) {
+ listenerInfo.notifyListener(FLAG_RESOURCE_OVERUSE_IO, uid, packageName,
+ resourceOveruseStats);
}
}
if (DEBUG) {
@@ -744,17 +737,21 @@
private void addResourceOveruseListenerLocked(
@CarWatchdogManager.ResourceOveruseFlag int resourceOveruseFlag,
@NonNull IResourceOveruseListener listener,
- SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
+ SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
boolean isListenerForSystem = listenerInfosByUid == mOveruseSystemListenerInfosByUid;
String listenerType = isListenerForSystem ? "resource overuse listener for system" :
"resource overuse listener";
- ResourceOveruseListenerInfo existingListenerInfo = listenerInfosByUid.get(callingUid, null);
- if (existingListenerInfo != null) {
- IBinder binder = listener.asBinder();
- if (existingListenerInfo.listener.asBinder() == binder) {
+ IBinder binder = listener.asBinder();
+ ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
+ if (listenerInfos == null) {
+ listenerInfos = new ArrayList<>();
+ listenerInfosByUid.put(callingUid, listenerInfos);
+ }
+ for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+ if (listenerInfo.listener.asBinder() == binder) {
throw new IllegalStateException(
"Cannot add " + listenerType + " as it is already added");
}
@@ -768,49 +765,44 @@
Slogf.w(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);
- existingListenerInfo.unlinkToDeath();
- }
-
-
- listenerInfosByUid.put(callingUid, listenerInfo);
+ listenerInfos.add(listenerInfo);
if (DEBUG) {
- Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType, callingPid,
- callingUid);
+ Slogf.d(TAG, "The %s (pid: %d, uid: %d) is added", listenerType,
+ callingPid, callingUid);
}
}
private void removeResourceOveruseListenerLocked(@NonNull IResourceOveruseListener listener,
- SparseArray<ResourceOveruseListenerInfo> listenerInfosByUid) {
+ SparseArray<ArrayList<ResourceOveruseListenerInfo>> listenerInfosByUid) {
int callingUid = Binder.getCallingUid();
-
String listenerType = listenerInfosByUid == mOveruseSystemListenerInfosByUid
? "resource overuse system listener" : "resource overuse listener";
-
- ResourceOveruseListenerInfo listenerInfo = listenerInfosByUid.get(callingUid, null);
- if (listenerInfo == null || listenerInfo.listener.asBinder() != listener.asBinder()) {
+ ArrayList<ResourceOveruseListenerInfo> listenerInfos = listenerInfosByUid.get(callingUid);
+ if (listenerInfos == null) {
Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
return;
}
- listenerInfo.unlinkToDeath();
- listenerInfosByUid.remove(callingUid);
- if (DEBUG) {
- Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType, listenerInfo.pid,
- listenerInfo.uid);
- }
- }
-
- private void onResourceOveruseListenerDeath(int uid, boolean isListenerForSystem) {
- synchronized (mLock) {
- if (isListenerForSystem) {
- mOveruseSystemListenerInfosByUid.remove(uid);
- } else {
- mOveruseListenerInfosByUid.remove(uid);
+ IBinder binder = listener.asBinder();
+ ResourceOveruseListenerInfo cachedListenerInfo = null;
+ for (ResourceOveruseListenerInfo listenerInfo : listenerInfos) {
+ if (listenerInfo.listener.asBinder() == binder) {
+ cachedListenerInfo = listenerInfo;
+ break;
}
}
+ if (cachedListenerInfo == null) {
+ Slogf.w(TAG, "Cannot remove the %s: it has not been registered before", listenerType);
+ return;
+ }
+ cachedListenerInfo.unlinkToDeath();
+ listenerInfos.remove(cachedListenerInfo);
+ if (listenerInfos.isEmpty()) {
+ listenerInfosByUid.remove(callingUid);
+ }
+ if (DEBUG) {
+ Slogf.d(TAG, "The %s (pid: %d, uid: %d) is removed", listenerType,
+ cachedListenerInfo.pid, cachedListenerInfo.uid);
+ }
}
@GuardedBy("mLock")
@@ -1306,10 +1298,42 @@
public void binderDied() {
Slogf.w(TAG, "Resource overuse listener%s (pid: %d) died",
isListenerForSystem ? " for system" : "", pid);
- onResourceOveruseListenerDeath(uid, isListenerForSystem);
+ Consumer<SparseArray<ArrayList<ResourceOveruseListenerInfo>>> removeListenerInfo =
+ listenerInfosByUid -> {
+ ArrayList<ResourceOveruseListenerInfo> listenerInfos =
+ listenerInfosByUid.get(uid);
+ if (listenerInfos == null) {
+ return;
+ }
+ listenerInfos.remove(this);
+ if (listenerInfos.isEmpty()) {
+ listenerInfosByUid.remove(uid);
+ }
+ };
+ if (isListenerForSystem) {
+ removeListenerInfo.accept(mOveruseSystemListenerInfosByUid);
+ } else {
+ removeListenerInfo.accept(mOveruseListenerInfosByUid);
+ }
unlinkToDeath();
}
+ public void notifyListener(@CarWatchdogManager.ResourceOveruseFlag int resourceType,
+ int overusingUid, String overusingPackage,
+ ResourceOveruseStats resourceOveruseStats) {
+ if ((flag & resourceType) == 0) {
+ return;
+ }
+ try {
+ listener.onOveruse(resourceOveruseStats);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "Failed to notify %s (uid %d, pid: %d) of resource overuse by "
+ + "package(uid %d, package '%s'): %s",
+ (isListenerForSystem ? "system listener" : "listener"), uid, pid,
+ overusingUid, overusingPackage, e);
+ }
+ }
+
private void linkToDeath() throws RemoteException {
listener.asBinder().linkToDeath(this, 0);
}
diff --git a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
index baf7675..f0cb1e7 100644
--- a/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
+++ b/tests/BugReportApp/src/com/android/car/bugreport/BugReportService.java
@@ -492,7 +492,8 @@
static void showBugReportFinishedNotification(Context context, MetaBugReport bug) {
Intent intent = new Intent(context, BugReportInfoActivity.class);
PendingIntent startBugReportInfoActivity =
- PendingIntent.getActivity(context, 0, intent, 0);
+ PendingIntent.getActivity(context.getApplicationContext(),
+ /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE);
Notification notification = new Notification
.Builder(context, STATUS_CHANNEL_ID)
.setContentTitle(context.getText(R.string.notification_bugreport_finished_title))
diff --git a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
index 6cc9160..098c7b2 100644
--- a/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
+++ b/tests/EmbeddedKitchenSinkApp/AndroidManifest.xml
@@ -156,6 +156,9 @@
</intent-filter>
</activity>
+ <activity android:name=".insets.WindowInsetsTestActivity"
+ android:label="@string/window_insets_test_activity"/>
+
<meta-data android:name="android.car.application"
android:resource="@xml/automotive_app_desc"/>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml b/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml
new file mode 100644
index 0000000..5c0957d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/fullscreen_activity.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:id="@+id/cancel_button"
+ android:text="@string/cancel"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml b/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml
new file mode 100644
index 0000000..890a6b2
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/toggle_fullscreen_fragment.xml
@@ -0,0 +1,27 @@
+<?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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/show_full_screen_button"
+ android:layout_gravity="center"
+ android:text="@string/nav_to_full_screen"/>
+</FrameLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index d02cce7..0613b45 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -366,10 +366,15 @@
<string name="empty_activity" translatable="false">Empty Activity</string>
<string name="audio_auto_start_activity" translatable="false">Audio Auto Start Activity</string>
<string name="occupant_zone_start_activity" translatable="false">Occupant Zone Start Activity</string>
+ <string name="window_insets_test_activity" translatable="false">Window Insets Test Activity</string>
<!-- ExperimentalFeatureTest -->
<string name="experimental_ping" translatable="false">Ping Service</string>
<!-- User Profile -->
<string name="status_message_title">Status Message</string>
+
+ <!-- Fullscreen Activity Test -->
+ <string name="nav_to_full_screen" translatable="false">Navigate to Full Screen</string>
+ <string name="cancel" translatable="false">Cancel</string>
</resources>
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 5012f46..beeac2a 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -59,6 +59,7 @@
import com.google.android.car.kitchensink.displayinfo.DisplayInfoFragment;
import com.google.android.car.kitchensink.experimental.ExperimentalFeatureTestFragment;
import com.google.android.car.kitchensink.hvac.HvacTestFragment;
+import com.google.android.car.kitchensink.insets.WindowInsetsFullScreenFragment;
import com.google.android.car.kitchensink.notification.NotificationFragment;
import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
import com.google.android.car.kitchensink.packageinfo.PackageInfoFragment;
@@ -211,7 +212,9 @@
new FragmentMenuEntry("vehicle hal", VehicleHalFragment.class),
new FragmentMenuEntry("volume test", VolumeTestFragment.class),
new FragmentMenuEntry("watchdog", CarWatchdogTestFragment.class),
- new FragmentMenuEntry("web links", WebLinksTestFragment.class));
+ new FragmentMenuEntry("web links", WebLinksTestFragment.class),
+ new FragmentMenuEntry("window insets full screen",
+ WindowInsetsFullScreenFragment.class));
private Car mCarApi;
private CarHvacManager mHvacManager;
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java
new file mode 100644
index 0000000..4140598
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsFullScreenFragment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.insets;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.car.kitchensink.R;
+
+/**
+ * Test fragment showing the transition to a full screen activity {@link WindowInsetsTestActivity}.
+ *
+ * The current fragment {@link WindowInsetsFullScreenFragment} and the activity
+ * {@link WindowInsetsTestActivity} has a view defined at the center of the screen to show the UX
+ * transition to/from full screen activity for fast tap cases.
+ */
+public final class WindowInsetsFullScreenFragment extends Fragment {
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.toggle_fullscreen_fragment, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ Button showFullScrnBtn = view.requireViewById(R.id.show_full_screen_button);
+ showFullScrnBtn.setOnClickListener(l -> navToFullScreen());
+ }
+
+ private void navToFullScreen() {
+ Intent intent = new Intent(getActivity(), WindowInsetsTestActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java
new file mode 100644
index 0000000..0afe369
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/insets/WindowInsetsTestActivity.java
@@ -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.
+ */
+
+package com.google.android.car.kitchensink.insets;
+
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
+
+import androidx.annotation.Nullable;
+
+import com.google.android.car.kitchensink.R;
+
+/**
+ * {@link WindowInsetsTestActivity} shows usage of {@link WindowInsetsController} api's to hide
+ * systems bars to present the activity in full screen.
+ */
+public final class WindowInsetsTestActivity extends Activity {
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ hideSysUI();
+
+ setContentView(R.layout.fullscreen_activity);
+ findViewById(R.id.cancel_button).setOnClickListener(l -> finish());
+ }
+
+ private void hideSysUI() {
+ View decorView = getWindow().getDecorView();
+ WindowInsetsController windowInsetsController = decorView.getWindowInsetsController();
+ windowInsetsController.hide(WindowInsets.Type.systemBars());
+ windowInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
+ }
+}
diff --git a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
index 43f07f4..18ee4a8 100644
--- a/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
+++ b/tests/NetworkPreferenceApp/src/com/google/android/car/networking/preferenceupdater/components/MetricDisplay.java
@@ -18,6 +18,9 @@
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.ROAMING_ALL;
+import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
+
+import static java.util.concurrent.TimeUnit.HOURS;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
@@ -32,6 +35,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.provider.Settings;
import android.util.Log;
import android.util.Pair;
@@ -76,7 +80,14 @@
mConnectivityManager = context.getSystemService(ConnectivityManager.class);
mNetStatsMan = context.getSystemService(NetworkStatsManager.class);
mMetricMessageHandler = handler;
- mStartTime = System.currentTimeMillis();
+
+ /* If the start time is set to the current time without accounting for bucket duration,
+ the reported rx/tx bytes will be inaccurate, since bucket sizes are on the order of
+ hours. This will manifest itself as the rx/tx values slowly climbing, even when there is
+ no network traffic. Setting the start time to one bucket duration prior to the current
+ time seems to fix this issue. */
+ mStartTime = System.currentTimeMillis() - Settings.Global.getLong(
+ mContext.getContentResolver(), NETSTATS_UID_BUCKET_DURATION, HOURS.toMillis(2));
scanAndPrintOemNetworksIfExist();
}
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
index 1ff7911..799e569 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarApiTestBase.java
@@ -26,13 +26,16 @@
import static org.junit.Assume.assumeFalse;
import android.annotation.NonNull;
+import android.app.UiAutomation;
import android.car.Car;
import android.content.ComponentName;
import android.content.Context;
import android.content.ServiceConnection;
+import android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType;
import android.os.Build;
import android.os.IBinder;
import android.os.Looper;
+import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
@@ -44,6 +47,11 @@
import org.junit.Rule;
import org.junit.rules.TestName;
+import java.io.BufferedReader;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -138,6 +146,8 @@
protected static void suspendToRamAndResume() throws Exception {
Log.d(TAG, "Emulate suspend to RAM and resume");
PowerManager powerManager = sContext.getSystemService(PowerManager.class);
+ // clear log
+ runShellCommand("logcat -b all -c");
runShellCommand("cmd car_service suspend");
// Check for suspend success
waitUntil("screen is still on after suspend",
@@ -146,6 +156,40 @@
// Force turn off garage mode
runShellCommand("cmd car_service garage-mode off");
runShellCommand("cmd car_service resume");
+ waitForLogcatMessage("logcat -b events", "car_user_svc_initial_user_info_req_complete: "
+ + InitialUserInfoRequestType.RESUME, 60_000);
+ }
+
+ /**
+ * Wait for a particular logcat message.
+ *
+ * @param cmd is logcat command with buffer or filters
+ * @param match is the string to be found in the log
+ * @param timeoutMs for which call should wait for the match
+ */
+ protected static void waitForLogcatMessage(String cmd, String match, int timeoutMs) {
+ Log.d(TAG, "waiting for logcat match: " + match);
+ long startTime = SystemClock.elapsedRealtime();
+ UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+ ParcelFileDescriptor output = automation.executeShellCommand(cmd);
+ FileDescriptor fd = output.getFileDescriptor();
+ FileInputStream fileInputStream = new FileInputStream(fd);
+ try (BufferedReader bufferedReader = new BufferedReader(
+ new InputStreamReader(fileInputStream))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains(match)) {
+ Log.d(TAG, "match found in "
+ + (SystemClock.elapsedRealtime() - startTime) + " ms");
+ break;
+ }
+ if ((SystemClock.elapsedRealtime() - startTime) > timeoutMs) {
+ fail("match was not found, Timeout: " + timeoutMs + " ms");
+ }
+ }
+ } catch (IOException e) {
+ fail("match was not found, IO exception: " + e);
+ }
}
protected static boolean waitUntil(String msg, long timeoutMs,
diff --git a/tests/carservice_unit_test/Android.bp b/tests/carservice_unit_test/Android.bp
index 57e14d9..cf9d238 100644
--- a/tests/carservice_unit_test/Android.bp
+++ b/tests/carservice_unit_test/Android.bp
@@ -69,6 +69,7 @@
// mockito-target-inline dependency
jni_libs: [
"libdexmakerjvmtiagent",
+ "libscriptexecutorjniutils-test",
"libstaticjvmtiagent",
],
}
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
index 1d1f9d0..ca3a301 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java
@@ -102,21 +102,38 @@
private static final String TAG = UserHalServiceTest.class.getSimpleName();
/**
- * Timeout passed to {@link UserHalService} methods
+ * Timeout passed to {@link UserHalService} methods. This is the timeout for which
+ * {@link UserHalService} wait for the property change event and return
+ * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} if HAL doesn't respond. This timeout is used
+ * where we expect HAL to return something and {@link UserHalService} methods are not expected
+ * to timeout. Tests are not supposed to wait for this much so this value can be high. If test
+ * requires HAL to timeout, then use {@link HAL_TIMEOUT_MS}.
*/
- private static final int TIMEOUT_MS = 50;
+ private static final int HAL_TIMEOUT_MS = 5_000;
/**
- * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is supposed to
- * return something - it's a short time so it doesn't impact the test duration.
+ * Timeout passed to {@link UserHalService} methods only if test expects that call will be
+ * timeout and {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is expected response. A higher
+ * value for this is going to slow down tests. If this timeout is used, then it is expected that
+ * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is checked.
*/
- private static final int CALLBACK_TIMEOUT_SUCCESS = TIMEOUT_MS + 50;
+ private static final int HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS = 250;
/**
- * Timeout for {@link GenericHalCallback#assertCalled()} for tests where the HAL is not supposed
- * to return anything - it's a slightly longer to make sure the test doesn't fail prematurely.
+ * If tests expect {@link UserHalService} call to timeout, and if they require to sleep then
+ * sleep for this much time. This value should be higher than {@link HAL_TIMEOUT_MS}. A much
+ * higher value for this is going to slow down the test.
*/
- private static final int CALLBACK_TIMEOUT_TIMEOUT = TIMEOUT_MS + 450;
+ private static final int WAITING_TIME_FOR_NEGATIVE_TESTS_MS = HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS
+ + 100;
+
+ /**
+ * Timeout for {@link GenericHalCallback#assertCalled()} for tests. In each case,
+ * {@link UserHalService} is supposed to return something - either a valid response or a
+ * timeout. This timeout is for the callback to wait for the response. A higher value of this
+ * timeout should not affect the test duration.
+ */
+ private static final int CALLBACK_TIMEOUT = 5_000;
// Used when crafting a request property - the real value will be set by the mock.
private static final int REQUEST_ID_PLACE_HOLDER = 1111;
@@ -254,7 +271,7 @@
UserHalService myHalService = new UserHalService(mVehicleHal);
assertThrows(IllegalStateException.class, () -> myHalService.getInitialUserInfo(COLD_BOOT,
- TIMEOUT_MS, mUsersInfo, noOpCallback()));
+ HAL_TIMEOUT_MS, mUsersInfo, noOpCallback()));
}
@Test
@@ -267,14 +284,14 @@
@Test
public void testGetUserInfo_noUsersInfo() {
- assertThrows(NullPointerException.class, () ->
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, null, noOpCallback()));
+ assertThrows(NullPointerException.class, () -> mUserHalService.getInitialUserInfo(COLD_BOOT,
+ HAL_TIMEOUT_MS, null, noOpCallback()));
}
@Test
public void testGetUserInfo_noCallback() {
assertThrows(NullPointerException.class,
- () -> mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS,
+ () -> mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS,
mUsersInfo, null));
}
@@ -283,8 +300,8 @@
replySetPropertyWithTimeoutException(INITIAL_USER_INFO);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -292,15 +309,15 @@
assertThat(callback.response).isNull();
// Make sure the pending request was removed
- SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+ SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
callback.assertNotCalledAgain();
}
@Test
public void testGetUserInfo_halDidNotReply() throws Exception {
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -311,12 +328,12 @@
@Test
public void testGetUserInfo_secondCallFailWhilePending() throws Exception {
GenericHalCallback<InitialUserInfoResponse> callback1 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
GenericHalCallback<InitialUserInfoResponse> callback2 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
callback1);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback2);
callback1.assertCalled();
@@ -337,8 +354,8 @@
/* rightRequestId= */ false);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -355,8 +372,8 @@
INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -378,8 +395,8 @@
INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -408,8 +425,8 @@
INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -441,8 +458,8 @@
INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true);
GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.getInitialUserInfo(COLD_BOOT, TIMEOUT_MS, mUsersInfo,
+ CALLBACK_TIMEOUT);
+ mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo,
callback);
callback.assertCalled();
@@ -475,7 +492,7 @@
assertThrows(IllegalStateException.class,
() -> myHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
- TIMEOUT_MS, noOpCallback()));
+ HAL_TIMEOUT_MS, noOpCallback()));
}
@Test
@@ -489,25 +506,27 @@
@Test
public void testSwitchUser_noUsersInfo() {
assertThrows(IllegalArgumentException.class, () -> mUserHalService
- .switchUser(createUserSwitchRequest(mUser10, null), TIMEOUT_MS, noOpCallback()));
+ .switchUser(createUserSwitchRequest(mUser10, null), HAL_TIMEOUT_MS,
+ noOpCallback()));
}
@Test
public void testSwitchUser_noCallback() {
assertThrows(NullPointerException.class, () -> mUserHalService
- .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS, null));
+ .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, null));
}
@Test
public void testSwitchUser_nullRequest() {
assertThrows(NullPointerException.class, () -> mUserHalService
- .switchUser(null, TIMEOUT_MS, noOpCallback()));
+ .switchUser(null, HAL_TIMEOUT_MS, noOpCallback()));
}
@Test
public void testSwitchUser_noTarget() {
assertThrows(NullPointerException.class, () -> mUserHalService
- .switchUser(createUserSwitchRequest(null, mUsersInfo), TIMEOUT_MS, noOpCallback()));
+ .switchUser(createUserSwitchRequest(null, mUsersInfo), HAL_TIMEOUT_MS,
+ noOpCallback()));
}
@Test
@@ -515,8 +534,9 @@
replySetPropertyWithTimeoutException(SWITCH_USER);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+ HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
callback);
callback.assertCalled();
@@ -524,15 +544,16 @@
assertThat(callback.response).isNull();
// Make sure the pending request was removed
- SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+ SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
callback.assertNotCalledAgain();
}
@Test
public void testSwitchUser_halDidNotReply() throws Exception {
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+ HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
callback);
callback.assertCalled();
@@ -549,8 +570,9 @@
/* rightRequestId= */ false);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+ HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
callback);
callback.assertCalled();
@@ -568,8 +590,8 @@
SWITCH_USER, propResponse, /* rightRequestId= */ true);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
callback);
callback.assertCalled();
@@ -593,8 +615,8 @@
SWITCH_USER, propResponse, /* rightRequestId= */ true);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
callback);
callback.assertCalled();
@@ -622,8 +644,8 @@
SWITCH_USER, propResponse, /* rightRequestId= */ true);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
callback);
callback.assertCalled();
@@ -643,12 +665,13 @@
@Test
public void testSwitchUser_secondCallFailWhilePending() throws Exception {
GenericHalCallback<SwitchUserResponse> callback1 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
GenericHalCallback<SwitchUserResponse> callback2 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo),
+ HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
callback1);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
callback2);
callback1.assertCalled();
@@ -670,8 +693,8 @@
SWITCH_USER, propResponse, /* rightRequestId= */ true);
GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), TIMEOUT_MS,
+ CALLBACK_TIMEOUT);
+ mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS,
callback);
callback.assertCalled();
@@ -869,13 +892,14 @@
UserHalService myHalService = new UserHalService(mVehicleHal);
assertThrows(IllegalStateException.class,
- () -> myHalService.createUser(new CreateUserRequest(), TIMEOUT_MS, noOpCallback()));
+ () -> myHalService.createUser(new CreateUserRequest(), HAL_TIMEOUT_MS,
+ noOpCallback()));
}
@Test
public void testCreateUser_noRequest() {
assertThrows(NullPointerException.class, () -> mUserHalService
- .createUser(null, TIMEOUT_MS, noOpCallback()));
+ .createUser(null, HAL_TIMEOUT_MS, noOpCallback()));
}
@Test
@@ -893,7 +917,7 @@
request.usersInfo.existingUsers.add(request.newUserInfo);
assertThrows(NullPointerException.class, () -> mUserHalService
- .createUser(request, TIMEOUT_MS, null));
+ .createUser(request, HAL_TIMEOUT_MS, null));
}
/**
@@ -912,23 +936,25 @@
replySetPropertyWithTimeoutException(CREATE_USER);
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+ callback);
callback.assertCalled();
assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
assertThat(callback.response).isNull();
// Make sure the pending request was removed
- SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+ SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
callback.assertNotCalledAgain();
}
@Test
public void testCreateUser_halDidNotReply() throws Exception {
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+ callback);
callback.assertCalled();
assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -944,8 +970,9 @@
/* rightRequestId= */ false);
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+ callback);
callback.assertCalled();
assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -965,8 +992,8 @@
request.newUserInfo = mUser10;
request.usersInfo = mUsersInfo;
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.createUser(request, TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback);
callback.assertCalled();
@@ -994,8 +1021,8 @@
request.newUserInfo = mUser10;
request.usersInfo = mUsersInfo;
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.createUser(request, TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback);
callback.assertCalled();
@@ -1012,11 +1039,12 @@
@Test
public void testCreateUser_secondCallFailWhilePending() throws Exception {
GenericHalCallback<CreateUserResponse> callback1 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
GenericHalCallback<CreateUserResponse> callback2 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback1);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback2);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS,
+ callback1);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback2);
callback1.assertCalled();
assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1037,8 +1065,8 @@
CREATE_USER, propResponse, /* rightRequestId= */ true);
GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_SUCCESS);
- mUserHalService.createUser(newValidCreateUserRequest(), TIMEOUT_MS, callback);
+ CALLBACK_TIMEOUT);
+ mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback);
callback.assertCalled();
@@ -1170,8 +1198,9 @@
// Cannot use mUserHalService because it's already set with supported properties
UserHalService myHalService = new UserHalService(mVehicleHal);
- assertThrows(IllegalStateException.class, () -> myHalService.setUserAssociation(TIMEOUT_MS,
- new UserIdentificationSetRequest(), noOpCallback()));
+ assertThrows(IllegalStateException.class,
+ () -> myHalService.setUserAssociation(HAL_TIMEOUT_MS,
+ new UserIdentificationSetRequest(), noOpCallback()));
}
@Test
@@ -1186,14 +1215,14 @@
@Test
public void testSetUserAssociation_nullRequest() {
assertThrows(NullPointerException.class, () ->
- mUserHalService.setUserAssociation(TIMEOUT_MS, null, noOpCallback()));
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, null, noOpCallback()));
}
@Test
public void testSetUserAssociation_nullCallback() {
UserIdentificationSetRequest request = new UserIdentificationSetRequest();
assertThrows(NullPointerException.class, () ->
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, null));
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, null));
}
@Test
@@ -1207,24 +1236,24 @@
request.associations.add(association1);
assertThrows(IllegalArgumentException.class, () ->
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, noOpCallback()));
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, noOpCallback()));
}
@Test
public void testSetUserAssociation_halSetTimedOut() throws Exception {
UserIdentificationSetRequest request = validUserIdentificationSetRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
replySetPropertyWithTimeoutException(USER_IDENTIFICATION_ASSOCIATION);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback);
callback.assertCalled();
assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT);
assertThat(callback.response).isNull();
// Make sure the pending request was removed
- SystemClock.sleep(CALLBACK_TIMEOUT_TIMEOUT);
+ SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS);
callback.assertNotCalledAgain();
}
@@ -1232,9 +1261,9 @@
public void testSetUserAssociation_halDidNotReply() throws Exception {
UserIdentificationSetRequest request = validUserIdentificationSetRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback);
callback.assertCalled();
assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1245,12 +1274,12 @@
public void testSetUserAssociation_secondCallFailWhilePending() throws Exception {
UserIdentificationSetRequest request = validUserIdentificationSetRequest();
GenericHalCallback<UserIdentificationResponse> callback1 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
GenericHalCallback<UserIdentificationResponse> callback2 = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback1);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback2);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback1);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback2);
callback1.assertCalled();
assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT);
@@ -1270,9 +1299,9 @@
USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
// Assert request
verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1295,9 +1324,9 @@
USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
// Assert request
verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1322,9 +1351,9 @@
USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
// Assert request
verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1347,9 +1376,9 @@
USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
// Assert request
verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1372,9 +1401,9 @@
USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true);
UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest();
GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>(
- CALLBACK_TIMEOUT_TIMEOUT);
+ CALLBACK_TIMEOUT);
- mUserHalService.setUserAssociation(TIMEOUT_MS, request, callback);
+ mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback);
// Assert request
verifyValidSetUserIdentificationRequestMade(propRequest.get());
@@ -1521,7 +1550,7 @@
* Run empty runnable to make sure that all posted handlers are done.
*/
private void waitForHandler() {
- mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT_TIMEOUT);
+ mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT);
}
private void mockNextRequestId(int requestId) {
@@ -1617,14 +1646,14 @@
@Override
public void onResponse(int status, R response) {
- Log.d(TAG, "onResponse(): status=" + status + ", response=" + response);
- this.status = status;
- this.response = response;
+ Log.d(TAG, "onResponse(): status=" + status + ", response=" + response);
if (mLatch.getCount() == 0) {
Log.e(TAG, "Already responded");
mExtraCalls.add(new Pair<>(status, response));
return;
}
+ this.status = status;
+ this.response = response;
mLatch.countDown();
}
diff --git a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
index 14824b2..5bc7974 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/SilentModeHandlerUnitTest.java
@@ -18,8 +18,6 @@
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -92,7 +90,6 @@
writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_SILENT_MODE);
assertWithMessage("Silent mode in forced mode").that(handler.isSilentMode()).isTrue();
- verify(mCarPowerManagementService, never()).notifySilentModeChange(anyBoolean());
}
@Test
@@ -107,7 +104,6 @@
writeStringToFile(mFileHwStateMonitoring.getFile(), VALUE_SILENT_MODE);
assertWithMessage("Silent mode in forced mode").that(handler.isSilentMode()).isFalse();
- verify(mCarPowerManagementService, never()).notifySilentModeChange(anyBoolean());
}
@Test
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
index d8bf9a2..0e9a168 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/CarTelemetryServiceTest.java
@@ -40,8 +40,8 @@
private final ManifestKey mManifestKeyV1 = new ManifestKey("Name", 1);
private final ManifestKey mManifestKeyV2 = new ManifestKey("Name", 2);
- private final TelemetryProto.Manifest mManifest =
- TelemetryProto.Manifest.newBuilder().setScript("no-op").build();
+ private final TelemetryProto.MetricsConfig mMetricsConfig =
+ TelemetryProto.MetricsConfig.newBuilder().setScript("no-op").build();
private CarTelemetryService mService;
@@ -52,16 +52,16 @@
@Test
public void testAddManifest_newManifest_shouldSucceed() {
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
@Test
public void testAddManifest_duplicateManifest_shouldFail() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_SAME_MANIFEST_EXISTS);
}
@@ -75,25 +75,25 @@
@Test
public void testAddManifest_olderManifest_shouldFail() {
- mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NEWER_MANIFEST_EXISTS);
}
@Test
public void testAddManifest_newerManifest_shouldReplace() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
- int result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
@Test
public void testRemoveManifest_manifestExists_shouldSucceed() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
boolean result = mService.removeManifest(mManifestKeyV1);
@@ -109,15 +109,15 @@
@Test
public void testRemoveAllManifests_shouldSucceed() {
- mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
- mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
+ mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
mService.removeAllManifests();
// verify that the manifests are cleared by adding them again, should succeed
- int result = mService.addManifest(mManifestKeyV1, mManifest.toByteArray());
+ int result = mService.addManifest(mManifestKeyV1, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
- result = mService.addManifest(mManifestKeyV2, mManifest.toByteArray());
+ result = mService.addManifest(mManifestKeyV2, mMetricsConfig.toByteArray());
assertThat(result).isEqualTo(CarTelemetryManager.ERROR_NONE);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java
new file mode 100644
index 0000000..67a5ac8
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/JniUtilsTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.telemetry;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class JniUtilsTest {
+
+ private static final String TAG = JniUtilsTest.class.getSimpleName();
+
+ private static final String BOOLEAN_KEY = "boolean_key";
+ private static final String INT_KEY = "int_key";
+ private static final String STRING_KEY = "string_key";
+ private static final String NUMBER_KEY = "number_key";
+
+ private static final boolean BOOLEAN_VALUE = true;
+ private static final double NUMBER_VALUE = 0.1;
+ private static final int INT_VALUE = 10;
+ private static final String STRING_VALUE = "test";
+
+ // Pointer to Lua Engine instantiated in native space.
+ private long mLuaEnginePtr = 0;
+
+ static {
+ System.loadLibrary("scriptexecutorjniutils-test");
+ }
+
+ @Before
+ public void setUp() {
+ mLuaEnginePtr = nativeCreateLuaEngine();
+ }
+
+ @After
+ public void tearDown() {
+ nativeDestroyLuaEngine(mLuaEnginePtr);
+ }
+
+ // Simply invokes PushBundleToLuaTable native method under test.
+ private native void nativePushBundleToLuaTableCaller(long luaEnginePtr, Bundle bundle);
+
+ // Creates an instance of LuaEngine on the heap and returns the pointer.
+ private native long nativeCreateLuaEngine();
+
+ // Destroys instance of LuaEngine on the native side at provided memory address.
+ private native void nativeDestroyLuaEngine(long luaEnginePtr);
+
+ // Returns size of a Lua object located at the specified position on the stack.
+ private native int nativeGetObjectSize(long luaEnginePtr, int index);
+
+ /*
+ * Family of methods to check if the table on top of the stack has
+ * the given value under provided key.
+ */
+ private native boolean nativeHasBooleanValue(long luaEnginePtr, String key, boolean value);
+ private native boolean nativeHasStringValue(long luaEnginePtr, String key, String value);
+ private native boolean nativeHasIntValue(long luaEnginePtr, String key, int value);
+ private native boolean nativeHasDoubleValue(long luaEnginePtr, String key, double value);
+
+ @Test
+ public void pushBundleToLuaTable_nullBundleMakesEmptyLuaTable() {
+ Log.d(TAG, "Using Lua Engine with address " + mLuaEnginePtr);
+ nativePushBundleToLuaTableCaller(mLuaEnginePtr, null);
+ // Get the size of the object on top of the stack,
+ // which is where our table is supposed to be.
+ assertThat(nativeGetObjectSize(mLuaEnginePtr, 1)).isEqualTo(0);
+ }
+
+ @Test
+ public void pushBundleToLuaTable_valuesOfDifferentTypes() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(BOOLEAN_KEY, BOOLEAN_VALUE);
+ bundle.putInt(INT_KEY, INT_VALUE);
+ bundle.putDouble(NUMBER_KEY, NUMBER_VALUE);
+ bundle.putString(STRING_KEY, STRING_VALUE);
+
+ // Invokes the corresponding helper method to convert the bundle
+ // to Lua table on Lua stack.
+ nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+ // Check contents of Lua table.
+ assertThat(nativeHasBooleanValue(mLuaEnginePtr, BOOLEAN_KEY, BOOLEAN_VALUE)).isTrue();
+ assertThat(nativeHasIntValue(mLuaEnginePtr, INT_KEY, INT_VALUE)).isTrue();
+ assertThat(nativeHasDoubleValue(mLuaEnginePtr, NUMBER_KEY, NUMBER_VALUE)).isTrue();
+ assertThat(nativeHasStringValue(mLuaEnginePtr, STRING_KEY, STRING_VALUE)).isTrue();
+ }
+
+
+ @Test
+ public void pushBundleToLuaTable_wrongKey() {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(BOOLEAN_KEY, BOOLEAN_VALUE);
+
+ // Invokes the corresponding helper method to convert the bundle
+ // to Lua table on Lua stack.
+ nativePushBundleToLuaTableCaller(mLuaEnginePtr, bundle);
+
+ // Check contents of Lua table.
+ assertThat(nativeHasBooleanValue(mLuaEnginePtr, "wrong key", BOOLEAN_VALUE)).isFalse();
+ }
+}
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 ac1b1e8..364a4ca 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
@@ -568,7 +568,7 @@
mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_SUCCESS);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- mCarUserService.stopUser(userId, userStopResult);
+ stopUser(userId, userStopResult);
assertThat(getResult(userStopResult).getStatus())
.isEqualTo(UserStopResult.STATUS_SUCCESSFUL);
@@ -582,8 +582,7 @@
mockManageUsersPermission(android.Manifest.permission.CREATE_USERS, false);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- assertThrows(SecurityException.class,
- () -> mCarUserService.stopUser(userId, userStopResult));
+ assertThrows(SecurityException.class, () -> stopUser(userId, userStopResult));
}
@Test
@@ -593,7 +592,7 @@
mockStopUserWithDelayedLockingThrowsRemoteException(userId);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- mCarUserService.stopUser(userId, userStopResult);
+ stopUser(userId, userStopResult);
assertThat(getResult(userStopResult).getStatus())
.isEqualTo(UserStopResult.STATUS_ANDROID_FAILURE);
@@ -607,7 +606,7 @@
mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_UNKNOWN_USER);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- mCarUserService.stopUser(userId, userStopResult);
+ stopUser(userId, userStopResult);
assertThat(getResult(userStopResult).getStatus())
.isEqualTo(UserStopResult.STATUS_USER_DOES_NOT_EXIST);
@@ -620,7 +619,7 @@
UserHandle.USER_SYSTEM, ActivityManager.USER_OP_ERROR_IS_SYSTEM);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- mCarUserService.stopUser(UserHandle.USER_SYSTEM, userStopResult);
+ stopUser(UserHandle.USER_SYSTEM, userStopResult);
assertThat(getResult(userStopResult).getStatus())
.isEqualTo(UserStopResult.STATUS_FAILURE_SYSTEM_USER);
@@ -634,7 +633,7 @@
mockStopUserWithDelayedLocking(userId, ActivityManager.USER_OP_IS_CURRENT);
AndroidFuture<UserStopResult> userStopResult = new AndroidFuture<>();
- mCarUserService.stopUser(userId, userStopResult);
+ stopUser(userId, userStopResult);
assertThat(getResult(userStopResult).getStatus())
.isEqualTo(UserStopResult.STATUS_FAILURE_CURRENT_USER);
@@ -1864,7 +1863,7 @@
mockAmStartUserInBackground(userId, true);
AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
- mCarUserService.startUserInBackground(userId, userStartResult);
+ startUserInBackground(userId, userStartResult);
assertThat(getResult(userStartResult).getStatus())
.isEqualTo(UserStartResult.STATUS_SUCCESSFUL);
@@ -1879,7 +1878,7 @@
AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
assertThrows(SecurityException.class,
- () -> mCarUserService.startUserInBackground(userId, userStartResult));
+ () -> startUserInBackground(userId, userStartResult));
}
@Test
@@ -1891,7 +1890,7 @@
mockAmStartUserInBackground(userId, false);
AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
- mCarUserService.startUserInBackground(userId, userStartResult);
+ startUserInBackground(userId, userStartResult);
assertThat(getResult(userStartResult).getStatus())
.isEqualTo(UserStartResult.STATUS_ANDROID_FAILURE);
@@ -1907,7 +1906,7 @@
mockAmStartUserInBackground(userId, true);
AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
- mCarUserService.startUserInBackground(userId, userStartResult);
+ startUserInBackground(userId, userStartResult);
assertThat(getResult(userStartResult).getStatus())
.isEqualTo(UserStartResult.STATUS_SUCCESSFUL_USER_IS_CURRENT_USER);
@@ -1922,7 +1921,7 @@
mockAmStartUserInBackground(userId, true);
AndroidFuture<UserStartResult> userStartResult = new AndroidFuture<>();
- mCarUserService.startUserInBackground(userId, userStartResult);
+ startUserInBackground(userId, userStartResult);
assertThat(getResult(userStartResult).getStatus())
.isEqualTo(UserStartResult.STATUS_USER_DOES_NOT_EXIST);
@@ -2357,6 +2356,18 @@
waitForHandlerThreadToFinish();
}
+ private void startUserInBackground(@UserIdInt int userId,
+ @NonNull AndroidFuture<UserStartResult> userStartResultFuture) {
+ mCarUserService.startUserInBackground(userId, userStartResultFuture);
+ waitForHandlerThreadToFinish();
+ }
+
+ private void stopUser(@UserIdInt int userId,
+ @NonNull AndroidFuture<UserStopResult> userStopResultFuture) {
+ mCarUserService.stopUser(userId, userStopResultFuture);
+ waitForHandlerThreadToFinish();
+ }
+
@NonNull
private UserSwitchResult getUserSwitchResult() throws Exception {
return getResult(mUserSwitchFuture);
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 ad47fa1..0014d57 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
@@ -87,6 +87,7 @@
import android.util.SparseArray;
import com.android.car.CarLog;
+import com.android.car.CarServiceUtils;
import com.android.internal.util.function.TriConsumer;
import com.google.common.truth.Correspondence;
@@ -97,7 +98,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
@@ -128,6 +128,9 @@
private CarWatchdogService mCarWatchdogService;
private ICarWatchdogServiceForSystem mWatchdogServiceForSystemImpl;
private IBinder.DeathRecipient mCarWatchdogDaemonBinderDeathRecipient;
+ private final SparseArray<String> mPackageNamesByUids = new SparseArray<>();
+ private final SparseArray<String[]> mSharedPackagesByUids = new SparseArray<>();
+ private final ArrayMap<String, ApplicationInfo> mApplicationInfosByPackages = new ArrayMap<>();
@Override
protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
@@ -151,6 +154,7 @@
mCarWatchdogService.init();
mWatchdogServiceForSystemImpl = registerCarWatchdogService();
captureDaemonBinderDeathRecipient();
+ mockPackageManager();
}
@Test
@@ -200,9 +204,7 @@
@Test
public void testGetResourceOveruseStats() throws Exception {
- SparseArray<String> packageNamesByUid = new SparseArray<>();
- packageNamesByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
- injectUidToPackageNameMapping(packageNamesByUid);
+ mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
constructPackageIoOveruseStats(
@@ -214,8 +216,9 @@
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
ResourceOveruseStats expectedStats =
- constructResourceOveruseStats(packageNamesByUid.keyAt(0),
- packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats);
+ constructResourceOveruseStats(mPackageNamesByUids.keyAt(0),
+ mPackageNamesByUids.valueAt(0),
+ packageIoOveruseStats.get(0).ioOveruseStats);
ResourceOveruseStats actualStats = mCarWatchdogService.getResourceOveruseStats(
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
@@ -239,18 +242,18 @@
@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);
+ mPackageNamesByUids.put(1103456, "third_party_package");
+ mPackageNamesByUids.put(1201278, "vendor_package.critical");
List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
- constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructPackageIoOveruseStats(mPackageNamesByUids.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,
+ constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+ /* shouldNotify= */false,
constructInternalIoOveruseStats(/* killableOnOveruse= */false,
/* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
/* writtenBytes= */constructPerStateBytes(5000, 6000, 9000),
@@ -258,10 +261,12 @@
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
List<ResourceOveruseStats> expectedStats = Arrays.asList(
- constructResourceOveruseStats(packageNamesByUid.keyAt(0),
- packageNamesByUid.valueAt(0), packageIoOveruseStats.get(0).ioOveruseStats),
- constructResourceOveruseStats(packageNamesByUid.keyAt(1),
- packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats));
+ constructResourceOveruseStats(mPackageNamesByUids.keyAt(0),
+ mPackageNamesByUids.valueAt(0),
+ packageIoOveruseStats.get(0).ioOveruseStats),
+ constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+ mPackageNamesByUids.valueAt(1),
+ packageIoOveruseStats.get(1).ioOveruseStats));
List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, /* minimumStatsFlag= */0,
@@ -297,18 +302,18 @@
@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);
+ mPackageNamesByUids.put(1103456, "third_party_package");
+ mPackageNamesByUids.put(1201278, "vendor_package.critical");
List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
- constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructPackageIoOveruseStats(mPackageNamesByUids.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,
+ constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+ /* shouldNotify= */false,
constructInternalIoOveruseStats(/* killableOnOveruse= */false,
/* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
/* writtenBytes= */constructPerStateBytes(7000000, 6000, 9000),
@@ -316,8 +321,9 @@
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
List<ResourceOveruseStats> expectedStats = Collections.singletonList(
- constructResourceOveruseStats(packageNamesByUid.keyAt(1),
- packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats));
+ constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+ mPackageNamesByUids.valueAt(1),
+ packageIoOveruseStats.get(1).ioOveruseStats));
List<ResourceOveruseStats> actualStats = mCarWatchdogService.getAllResourceOveruseStats(
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
@@ -330,18 +336,18 @@
@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);
+ mPackageNamesByUids.put(1103456, "third_party_package");
+ mPackageNamesByUids.put(1201278, "vendor_package.critical");
List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
- constructPackageIoOveruseStats(packageNamesByUid.keyAt(0), /* shouldNotify= */false,
+ constructPackageIoOveruseStats(mPackageNamesByUids.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,
+ constructPackageIoOveruseStats(mPackageNamesByUids.keyAt(1),
+ /* shouldNotify= */false,
constructInternalIoOveruseStats(/* killableOnOveruse= */false,
/* remainingWriteBytes= */constructPerStateBytes(450, 120, 340),
/* writtenBytes= */constructPerStateBytes(500, 600, 900),
@@ -349,8 +355,9 @@
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
ResourceOveruseStats expectedStats =
- constructResourceOveruseStats(packageNamesByUid.keyAt(1),
- packageNamesByUid.valueAt(1), packageIoOveruseStats.get(1).ioOveruseStats);
+ constructResourceOveruseStats(mPackageNamesByUids.keyAt(1),
+ mPackageNamesByUids.valueAt(1),
+ packageIoOveruseStats.get(1).ioOveruseStats);
ResourceOveruseStats actualStats =
mCarWatchdogService.getResourceOveruseStatsForUserPackage(
@@ -402,40 +409,111 @@
@Test
public void testResourceOveruseListener() throws Exception {
- int callingUid = Binder.getCallingUid();
- SparseArray<String> packageNamesByUid = new SparseArray<>();
- packageNamesByUid.put(callingUid, "critical.system.package");
- injectUidToPackageNameMapping(packageNamesByUid);
+ mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
IResourceOveruseListener mockListener = createMockResourceOveruseListener();
+ IBinder mockBinder = mockListener.asBinder();
+
mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
mockListener);
- IBinder mockBinder = mockListener.asBinder();
verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- List<PackageIoOveruseStats> packageIoOveruseStats = Collections.singletonList(
- constructPackageIoOveruseStats(callingUid, /* shouldNotify= */true,
- constructInternalIoOveruseStats(/* killableOnOveruse= */true,
- /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
- /* writtenBytes= */constructPerStateBytes(100, 200, 300),
- /* totalOveruses= */2)));
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>(
+ Collections.singleton(mMockContext.getPackageName())));
- mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
-
- verify(mockListener, times(1)).onOveruse(any());
+ verify(mockListener).onOveruse(any());
mCarWatchdogService.removeResourceOveruseListener(mockListener);
verify(mockListener, atLeastOnce()).asBinder();
verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>(
+ Collections.singletonList(mMockContext.getPackageName())));
verifyNoMoreInteractions(mockListener);
}
@Test
+ public void testDuplicateAddResourceOveruseListener() throws Exception {
+ mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+
+ IResourceOveruseListener mockListener = createMockResourceOveruseListener();
+ IBinder mockBinder = mockListener.asBinder();
+
+ mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ mockListener);
+
+ assertThrows(IllegalStateException.class,
+ () -> mCarWatchdogService.addResourceOveruseListener(
+ CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mockListener));
+
+ verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mCarWatchdogService.removeResourceOveruseListener(mockListener);
+
+ verify(mockListener, atLeastOnce()).asBinder();
+ verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ verifyNoMoreInteractions(mockListener);
+ }
+
+ @Test
+ public void testAddMultipleResourceOveruseListeners() throws Exception {
+ mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+
+ IResourceOveruseListener firstMockListener = createMockResourceOveruseListener();
+ IBinder firstMockBinder = firstMockListener.asBinder();
+ IResourceOveruseListener secondMockListener = createMockResourceOveruseListener();
+ IBinder secondMockBinder = secondMockListener.asBinder();
+
+ mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ firstMockListener);
+ mCarWatchdogService.addResourceOveruseListener(CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
+ secondMockListener);
+
+ verify(firstMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ verify(secondMockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>(
+ Collections.singleton(mMockContext.getPackageName())));
+
+ verify(firstMockListener).onOveruse(any());
+
+ mCarWatchdogService.removeResourceOveruseListener(firstMockListener);
+
+ verify(firstMockListener, atLeastOnce()).asBinder();
+ verify(firstMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>(
+ Collections.singletonList(mMockContext.getPackageName())));
+
+ verify(secondMockListener, times(2)).onOveruse(any());
+
+ mCarWatchdogService.removeResourceOveruseListener(secondMockListener);
+
+ verify(secondMockListener, atLeastOnce()).asBinder();
+ verify(secondMockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>(
+ Collections.singletonList(mMockContext.getPackageName())));
+
+ verifyNoMoreInteractions(firstMockListener);
+ verifyNoMoreInteractions(secondMockListener);
+ }
+
+ @Test
public void testAddResourceOveruseListenerForSystemThrowsWithInvalidFlag() throws Exception {
IResourceOveruseListener mockListener = createMockResourceOveruseListener();
assertThrows(IllegalArgumentException.class, () -> {
@@ -446,9 +524,7 @@
@Test
public void testResourceOveruseListenerForSystem() throws Exception {
int callingUid = Binder.getCallingUid();
- SparseArray<String> packageNamesByUid = new SparseArray<>();
- packageNamesByUid.put(callingUid, "critical.system.package");
- injectUidToPackageNameMapping(packageNamesByUid);
+ mPackageNamesByUids.put(callingUid, "critical.system.package");
IResourceOveruseListener mockListener = createMockResourceOveruseListener();
mCarWatchdogService.addResourceOveruseListenerForSystem(
@@ -466,7 +542,7 @@
mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
- verify(mockListener, times(1)).onOveruse(any());
+ verify(mockListener).onOveruse(any());
mCarWatchdogService.removeResourceOveruseListenerForSystem(mockListener);
@@ -483,11 +559,12 @@
mockUmGetAliveUsers(mMockUserManager, 11, 12);
injectPackageInfos(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")));
+ mPackageNamesByUids.put(1103456, "third_party_package");
+ mPackageNamesByUids.put(1101278, "vendor_package.critical");
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(
+ Collections.singletonList("third_party_package")),
+ /* shouldNotifyPackages= */new ArraySet<>());
UserHandle userHandle = new UserHandle(11);
@@ -555,11 +632,12 @@
mockUmGetAliveUsers(mMockUserManager, 11, 12);
injectPackageInfos(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")));
+ mPackageNamesByUids.put(1103456, "third_party_package");
+ mPackageNamesByUids.put(1101278, "vendor_package.critical");
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(
+ Collections.singletonList("third_party_package")),
+ /* shouldNotifyPackages= */new ArraySet<>());
mCarWatchdogService.setKillablePackageAsUser("third_party_package", UserHandle.ALL,
/* isKillable= */ true);
@@ -893,12 +971,10 @@
int nonCriticalVndrPkgUid = getUid(2564);
int thirdPartyPkgUid = getUid(2044);
- SparseArray<String> packageNamesByUid = new SparseArray<>();
- packageNamesByUid.put(criticalSysPkgUid, "critical.system.package");
- packageNamesByUid.put(nonCriticalSysPkgUid, "non_critical.system.package");
- packageNamesByUid.put(nonCriticalVndrPkgUid, "non_critical.vendor.package");
- packageNamesByUid.put(thirdPartyPkgUid, "third_party.package");
- injectUidToPackageNameMapping(packageNamesByUid);
+ mPackageNamesByUids.put(criticalSysPkgUid, "critical.system.package");
+ mPackageNamesByUids.put(nonCriticalSysPkgUid, "non_critical.system.package");
+ mPackageNamesByUids.put(nonCriticalVndrPkgUid, "non_critical.vendor.package");
+ mPackageNamesByUids.put(thirdPartyPkgUid, "third_party.package");
IResourceOveruseListener mockSystemListener = createMockResourceOveruseListener();
mCarWatchdogService.addResourceOveruseListenerForSystem(
@@ -943,31 +1019,31 @@
List<ResourceOveruseStats> expectedStats = new ArrayList<>();
expectedStats.add(constructResourceOveruseStats(criticalSysPkgUid,
- packageNamesByUid.get(criticalSysPkgUid),
+ mPackageNamesByUids.get(criticalSysPkgUid),
packageIoOveruseStats.get(0).ioOveruseStats));
verifyOnOveruseCalled(expectedStats, mockListener);
expectedStats.add(constructResourceOveruseStats(nonCriticalSysPkgUid,
- packageNamesByUid.get(nonCriticalSysPkgUid),
+ mPackageNamesByUids.get(nonCriticalSysPkgUid),
packageIoOveruseStats.get(1).ioOveruseStats));
expectedStats.add(constructResourceOveruseStats(thirdPartyPkgUid,
- packageNamesByUid.get(thirdPartyPkgUid),
+ mPackageNamesByUids.get(thirdPartyPkgUid),
packageIoOveruseStats.get(3).ioOveruseStats));
verifyOnOveruseCalled(expectedStats, mockSystemListener);
- verify(packageManagerService, times(1)).getApplicationEnabledSetting(
- packageNamesByUid.get(thirdPartyPkgUid), UserHandle.getUserId(thirdPartyPkgUid));
- verify(packageManagerService, times(1)).setApplicationEnabledSetting(
- eq(packageNamesByUid.get(thirdPartyPkgUid)), anyInt(), anyInt(),
+ verify(packageManagerService).getApplicationEnabledSetting(
+ mPackageNamesByUids.get(thirdPartyPkgUid), UserHandle.getUserId(thirdPartyPkgUid));
+ verify(packageManagerService).setApplicationEnabledSetting(
+ eq(mPackageNamesByUids.get(thirdPartyPkgUid)), anyInt(), anyInt(),
eq(UserHandle.getUserId(thirdPartyPkgUid)), anyString());
List<PackageResourceOveruseAction> expectedActions = Arrays.asList(
- constructPackageResourceOveruseAction(packageNamesByUid.get(criticalSysPkgUid),
+ constructPackageResourceOveruseAction(mPackageNamesByUids.get(criticalSysPkgUid),
criticalSysPkgUid, new int[]{ResourceType.IO}, NOT_KILLED),
- constructPackageResourceOveruseAction(packageNamesByUid.get(thirdPartyPkgUid),
+ constructPackageResourceOveruseAction(mPackageNamesByUids.get(thirdPartyPkgUid),
thirdPartyPkgUid, new int[]{ResourceType.IO}, KILLED));
verifyActionsTakenOnResourceOveruse(expectedActions);
}
@@ -987,25 +1063,11 @@
@Test
public void testResetResourceOveruseStats() throws Exception {
- SparseArray<String> packageNamesByUid = new SparseArray<>();
- packageNamesByUid.put(Binder.getCallingUid(), mMockContext.getPackageName());
- packageNamesByUid.put(1101278, "vendor_package.critical");
- injectUidToPackageNameMapping(packageNamesByUid);
-
- List<PackageIoOveruseStats> packageIoOveruseStats = Arrays.asList(
- constructPackageIoOveruseStats(
- Binder.getCallingUid(), /* shouldNotify= */false,
- constructInternalIoOveruseStats(/* killableOnOveruse= */false,
- /* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
- /* writtenBytes= */constructPerStateBytes(100, 200, 300),
- /* totalOveruses= */2)),
- constructPackageIoOveruseStats(
- 1101278, /* shouldNotify= */false,
- constructInternalIoOveruseStats(/* killableOnOveruse= */false,
- /* remainingWriteBytes= */constructPerStateBytes(120, 220, 230),
- /* writtenBytes= */constructPerStateBytes(3100, 5200, 6300),
- /* totalOveruses= */3)));
- mWatchdogServiceForSystemImpl.latestIoOveruseStats(packageIoOveruseStats);
+ mPackageNamesByUids.put(Binder.getCallingUid(), mMockContext.getPackageName());
+ mPackageNamesByUids.put(1101278, "vendor_package.critical");
+ injectIoOveruseStatsForPackages(mPackageNamesByUids,
+ /* killablePackages= */new ArraySet<>(),
+ /* shouldNotifyPackages= */new ArraySet<>());
mWatchdogServiceForSystemImpl.resetResourceOveruseStats(
Collections.singletonList(mMockContext.getPackageName()));
@@ -1049,25 +1111,29 @@
UidType.APPLICATION, ComponentType.VENDOR,
ApplicationCategoryType.OTHERS));
- ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(9);
- applicationInfos.put("system.package.A",
- constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
- applicationInfos.put("system.package.B",
- constructApplicationInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0));
- applicationInfos.put("system.package.F",
- constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_PRODUCT));
- applicationInfos.put("vendor.package.D",
- constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_OEM));
- applicationInfos.put("vendor.package.E",
- constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_VENDOR));
- applicationInfos.put("vendor.package.J",
- constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_ODM));
- applicationInfos.put("third_party.package.C", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.G", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.H", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.I", constructApplicationInfo(0, 0));
+ for (PackageInfo packageInfo : expectedPackageInfos) {
+ mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.packageIdentifier.name);
+ mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.sharedUidPackages.toArray(new String[0]));
+ }
- mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+ mApplicationInfosByPackages.put("system.package.A",
+ constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
+ mApplicationInfosByPackages.put("system.package.B",
+ constructApplicationInfo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0));
+ mApplicationInfosByPackages.put("system.package.F",
+ constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_PRODUCT));
+ mApplicationInfosByPackages.put("vendor.package.D",
+ constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_OEM));
+ mApplicationInfosByPackages.put("vendor.package.E",
+ constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_VENDOR));
+ mApplicationInfosByPackages.put("vendor.package.J",
+ constructApplicationInfo(0, ApplicationInfo.PRIVATE_FLAG_ODM));
+ mApplicationInfosByPackages.put("third_party.package.C", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.G", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.H", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.I", constructApplicationInfo(0, 0));
List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
uids, new ArrayList<>());
@@ -1092,21 +1158,25 @@
new ArrayList<>(), UidType.APPLICATION, ComponentType.THIRD_PARTY,
ApplicationCategoryType.OTHERS));
- ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(5);
- applicationInfos.put("vendor.package.D", constructApplicationInfo(0,
+ for (PackageInfo packageInfo : expectedPackageInfos) {
+ mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.packageIdentifier.name);
+ mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.sharedUidPackages.toArray(new String[0]));
+ }
+
+ mApplicationInfosByPackages.put("vendor.package.D", constructApplicationInfo(0,
ApplicationInfo.PRIVATE_FLAG_PRODUCT));
- applicationInfos.put("vendor.pkg.E", constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM,
- 0));
+ mApplicationInfosByPackages.put("vendor.pkg.E",
+ constructApplicationInfo(ApplicationInfo.FLAG_SYSTEM, 0));
/*
* A 3p package pretending to be a vendor package because 3p packages won't have the
* required flags.
*/
- applicationInfos.put("vendor.package.imposter", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.F", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.G", constructApplicationInfo(0, 0));
- applicationInfos.put("third_party.package.H", constructApplicationInfo(0, 0));
-
- mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+ mApplicationInfosByPackages.put("vendor.package.imposter", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.F", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.G", constructApplicationInfo(0, 0));
+ mApplicationInfosByPackages.put("third_party.package.H", constructApplicationInfo(0, 0));
List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
uids, Arrays.asList("vendor.package.", "vendor.pkg."));
@@ -1132,17 +1202,18 @@
UidType.APPLICATION, ComponentType.UNKNOWN,
ApplicationCategoryType.OTHERS));
- ArrayMap<String, ApplicationInfo> applicationInfos = new ArrayMap<>(3);
- applicationInfos.put(
- "vendor.package.D", constructApplicationInfo(0,
- ApplicationInfo.PRIVATE_FLAG_VENDOR));
- applicationInfos.put(
- "vendor.package.E", constructApplicationInfo(0,
- ApplicationInfo.PRIVATE_FLAG_VENDOR));
- applicationInfos.put(
- "third_party.package.F", constructApplicationInfo(0, 0));
+ for (PackageInfo packageInfo : expectedPackageInfos) {
+ mPackageNamesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.packageIdentifier.name);
+ mSharedPackagesByUids.put(packageInfo.packageIdentifier.uid,
+ packageInfo.sharedUidPackages.toArray(new String[0]));
+ }
- mockPackageManager(uids, expectedPackageInfos, applicationInfos);
+ mApplicationInfosByPackages.put("vendor.package.D", constructApplicationInfo(0,
+ ApplicationInfo.PRIVATE_FLAG_VENDOR));
+ mApplicationInfosByPackages.put("vendor.package.E", constructApplicationInfo(0,
+ ApplicationInfo.PRIVATE_FLAG_VENDOR));
+ mApplicationInfosByPackages.put("third_party.package.F", constructApplicationInfo(0, 0));
List<PackageInfo> actualPackageInfos = mWatchdogServiceForSystemImpl.getPackageInfosForUids(
uids, new ArrayList<>());
@@ -1156,10 +1227,38 @@
doReturn(mMockBinder).when(() -> ServiceManager.getService(CAR_WATCHDOG_DAEMON_INTERFACE));
}
+ private void mockPackageManager() throws Exception {
+ mPackageNamesByUids.clear();
+ mSharedPackagesByUids.clear();
+ mApplicationInfosByPackages.clear();
+ when(mMockPackageManager.getNamesForUids(any())).thenAnswer(args -> {
+ int[] uids = args.getArgument(0);
+ String[] packageNames = new String[uids.length];
+ for (int i = 0; i < uids.length; ++i) {
+ packageNames[i] = mPackageNamesByUids.get(uids[i], null);
+ }
+ return packageNames;
+ });
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenAnswer(
+ args -> mSharedPackagesByUids.get(args.getArgument(0), null));
+
+ when(mMockPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenAnswer(
+ args -> {
+ String packageName = args.getArgument(0);
+ ApplicationInfo applicationInfo = mApplicationInfosByPackages
+ .getOrDefault(packageName, /* defaultValue= */ null);
+ if (applicationInfo == null) {
+ throw new PackageManager.NameNotFoundException(
+ "Package " + packageName + " not found exception");
+ }
+ return applicationInfo;
+ });
+ }
+
private void captureDaemonBinderDeathRecipient() throws Exception {
ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor =
ArgumentCaptor.forClass(IBinder.DeathRecipient.class);
- verify(mMockBinder, timeout(MAX_WAIT_TIME_MS))
+ verify(mMockBinder, timeout(MAX_WAIT_TIME_MS).atLeastOnce())
.linkToDeath(deathRecipientCaptor.capture(), anyInt());
mCarWatchdogDaemonBinderDeathRecipient = deathRecipientCaptor.getValue();
}
@@ -1185,11 +1284,14 @@
}
private ICarWatchdogServiceForSystem registerCarWatchdogService() throws Exception {
+ /* Registering to daemon is done on the main thread. To ensure the registration completes
+ * before verification, execute an empty block on the main thread.
+ */
+ CarServiceUtils.runOnMainSync(() -> {});
+
ArgumentCaptor<ICarWatchdogServiceForSystem> watchdogServiceForSystemImplCaptor =
ArgumentCaptor.forClass(ICarWatchdogServiceForSystem.class);
- // Registering to daemon is done through a message handler. So, a buffer time of 1000ms is
- // given.
- verify(mMockCarWatchdogDaemon, timeout(1000)).registerCarWatchdogService(
+ verify(mMockCarWatchdogDaemon, atLeastOnce()).registerCarWatchdogService(
watchdogServiceForSystemImplCaptor.capture());
return watchdogServiceForSystemImplCaptor.getValue();
}
@@ -1216,26 +1318,14 @@
return resourceOveruseConfigurationsCaptor.getValue();
}
- private void injectUidToPackageNameMapping(SparseArray<String> packageNamesByUid) {
- when(mMockPackageManager.getNamesForUids(any())).thenAnswer(args -> {
- int[] uids = args.getArgument(0);
- String[] packageNames = new String[uids.length];
- for (int i = 0; i < uids.length; ++i) {
- packageNames[i] = packageNamesByUid.get(uids[i], null);
- }
- return packageNames;
- });
- }
-
private void injectIoOveruseStatsForPackages(SparseArray<String> packageNamesByUid,
- Set<String> killablePackages) throws Exception {
- injectUidToPackageNameMapping(packageNamesByUid);
+ Set<String> killablePackages, Set<String> shouldNotifyPackages) throws Exception {
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,
+ shouldNotifyPackages.contains(packageName),
constructInternalIoOveruseStats(killablePackages.contains(packageName),
/* remainingWriteBytes= */constructPerStateBytes(20, 20, 20),
/* writtenBytes= */constructPerStateBytes(100, 200, 300),
@@ -1530,30 +1620,6 @@
return listener;
}
- private void mockPackageManager(int[] uids, List<PackageInfo> packageInfos,
- ArrayMap<String, ApplicationInfo> applicationInfos)
- throws Exception {
- String[] packageNames = new String[packageInfos.size()];
- for (int i = 0; i < packageInfos.size(); ++i) {
- PackageInfo packageInfo = packageInfos.get(i);
- packageNames[i] = packageInfo.packageIdentifier.name;
- when(mMockPackageManager.getPackagesForUid(packageInfo.packageIdentifier.uid))
- .thenReturn(packageInfo.sharedUidPackages.toArray(new String[0]));
- }
- when(mMockPackageManager.getNamesForUids(any())).thenReturn(packageNames);
- when(mMockPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenAnswer(
- (InvocationOnMock invocation) -> {
- String packageName = invocation.getArgument(0);
- ApplicationInfo applicationInfo = applicationInfos
- .getOrDefault(packageName, /* defaultValue= */ null);
- if (applicationInfo == null) {
- throw new PackageManager.NameNotFoundException(
- "Package " + packageName + " not found exception");
- }
- return applicationInfo;
- });
- }
-
private static PackageInfo constructPackageInfo(String packageName, int uid,
List<String> sharedUidPackages, int uidType, int componentType, int appCategoryType) {
PackageInfo packageInfo = new PackageInfo();