Add system monitor event class, set DataBroker priority when receives
event.

- The SystemMonitorEvent contains system status
- DataBrokerController uses the event to determine the appropriate task
priority to run for DataBroker

Bug: 187744195
Test: atest CarServiceUnitTest:DataBrokerControllerUnitTest
Test: atest CarServiceUnitTest:SystemMonitorEventUnitTest
Change-Id: I18087dc3f44e26000932afd3110f0ee6c5a38482
diff --git a/service/src/com/android/car/telemetry/databroker/DataBroker.java b/service/src/com/android/car/telemetry/databroker/DataBroker.java
index e26b113..44f2f61 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBroker.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBroker.java
@@ -48,4 +48,10 @@
      * @param callback script finished callback.
      */
     void setOnScriptFinishedCallback(DataBrokerController.ScriptFinishedCallback callback);
+
+    /**
+     * Invoked by controller to indicate system health state and which subscribers can be consumed.
+     * A smaller priority number indicates higher priority. Range 1 - 100.
+     */
+    void setTaskExecutionPriority(int priority);
 }
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
index 75bfd78..7663667 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerController.java
@@ -17,6 +17,8 @@
 package com.android.car.telemetry.databroker;
 
 import com.android.car.telemetry.TelemetryProto.MetricsConfig;
+import com.android.car.telemetry.systemmonitor.SystemMonitor;
+import com.android.car.telemetry.systemmonitor.SystemMonitorEvent;
 
 /**
  * DataBrokerController instantiates the DataBroker and manages what Publishers
@@ -24,8 +26,13 @@
  */
 public class DataBrokerController {
 
+    public static final int TASK_PRIORITY_HI = 0;
+    public static final int TASK_PRIORITY_MED = 50;
+    public static final int TASK_PRIORITY_LOW = 100;
+
     private MetricsConfig mMetricsConfig;
     private final DataBroker mDataBroker;
+    private final SystemMonitor mSystemMonitor;
 
     /**
      * Interface for receiving notification that script finished.
@@ -39,21 +46,11 @@
         void onScriptFinished(String configName);
     }
 
-    /**
-     * Interface for receiving notification about metric config changes.
-     */
-    public interface MetricsConfigCallback {
-        /**
-         * Listens to new metrics config event.
-         *
-         * @param metricsConfig the new metrics config.
-         */
-        void onNewMetricsConfig(MetricsConfig metricsConfig);
-    }
-
-    public DataBrokerController(DataBroker dataBroker) {
+    public DataBrokerController(DataBroker dataBroker, SystemMonitor systemMonitor) {
         mDataBroker = dataBroker;
         mDataBroker.setOnScriptFinishedCallback(this::onScriptFinished);
+        mSystemMonitor = systemMonitor;
+        mSystemMonitor.setSystemMonitorCallback(this::onSystemMonitorEvent);
     }
 
     /**
@@ -72,6 +69,27 @@
      * @param configName the name of the config of the finished script.
      */
     public void onScriptFinished(String configName) {
-        // TODO(b/187744195): remove finished config from config store
+        // TODO(b/192008783): remove finished config from config store
+    }
+
+    /**
+     * Listens to {@link SystemMonitorEvent} and changes the cut-off priority
+     * for {@link DataBroker} such that only tasks with the same or more urgent
+     * priority can be run.
+     *
+     * Highest priority is 0 and lowest is 100.
+     *
+     * @param event the {@link SystemMonitorEvent} received.
+     */
+    public void onSystemMonitorEvent(SystemMonitorEvent event) {
+        if (event.getCpuUsageLevel() == SystemMonitorEvent.USAGE_LEVEL_HI
+                || event.getMemoryUsageLevel() == SystemMonitorEvent.USAGE_LEVEL_HI) {
+            mDataBroker.setTaskExecutionPriority(TASK_PRIORITY_HI);
+        } else if (event.getCpuUsageLevel() == SystemMonitorEvent.USAGE_LEVEL_MED
+                    || event.getMemoryUsageLevel() == SystemMonitorEvent.USAGE_LEVEL_MED) {
+            mDataBroker.setTaskExecutionPriority(TASK_PRIORITY_MED);
+        } else {
+            mDataBroker.setTaskExecutionPriority(TASK_PRIORITY_LOW);
+        }
     }
 }
diff --git a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
index 0a46536..86d725e 100644
--- a/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
+++ b/service/src/com/android/car/telemetry/databroker/DataBrokerImpl.java
@@ -47,6 +47,9 @@
         mPublisherFactory = publisherFactory;
     }
 
+    // current task priority, used to determine which data can be processed
+    private int mTaskExecutionPriority;
+
     @Override
     public boolean addMetricsConfiguration(MetricsConfig metricsConfig) {
         // if metricsConfig already exists, it should not be added again
@@ -104,6 +107,11 @@
         mScriptFinishedCallback = callback;
     }
 
+    @Override
+    public void setTaskExecutionPriority(int priority) {
+        mTaskExecutionPriority = priority;
+    }
+
     @VisibleForTesting
     Map<String, List<DataSubscriber>> getSubscriptionMap() {
         return mSubscriptionMap;
diff --git a/service/src/com/android/car/telemetry/systemmonitor/SystemMonitor.java b/service/src/com/android/car/telemetry/systemmonitor/SystemMonitor.java
new file mode 100644
index 0000000..65bc45b
--- /dev/null
+++ b/service/src/com/android/car/telemetry/systemmonitor/SystemMonitor.java
@@ -0,0 +1,47 @@
+/*
+ * 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.systemmonitor;
+
+/**
+ * SystemMonitor monitors system states and report to listeners when there are
+ * important changes.
+ */
+public class SystemMonitor {
+
+    private SystemMonitorCallback mCallback;
+
+    /**
+     * Interface for receiving notifications about system monitor changes.
+     */
+    public interface SystemMonitorCallback {
+        /**
+         * Listens to system monitor event.
+         *
+         * @param event the system monitor event.
+         */
+        void onSystemMonitorEvent(SystemMonitorEvent event);
+    }
+
+    /**
+     * Sets the callback to notify of system state changes.
+     *
+     * @param callback the callback to nofify state changes on.
+     */
+    public void setSystemMonitorCallback(SystemMonitorCallback callback) {
+        mCallback = callback;
+    }
+}
diff --git a/service/src/com/android/car/telemetry/systemmonitor/SystemMonitorEvent.java b/service/src/com/android/car/telemetry/systemmonitor/SystemMonitorEvent.java
new file mode 100644
index 0000000..67a7dbd
--- /dev/null
+++ b/service/src/com/android/car/telemetry/systemmonitor/SystemMonitorEvent.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.systemmonitor;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * System health events emitted by the SystemMonitor.
+ */
+public class SystemMonitorEvent {
+
+    @IntDef(prefix = { "USAGE_LEVEL_" },
+            value = { USAGE_LEVEL_LOW, USAGE_LEVEL_MED, USAGE_LEVEL_HI })
+
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UsageLevel {}
+
+    public static final int USAGE_LEVEL_LOW = 0;
+
+    public static final int USAGE_LEVEL_MED = 1;
+
+    public static final int USAGE_LEVEL_HI = 2;
+
+    private @UsageLevel int mCpuUsageLevel;
+
+    private @UsageLevel int mMemoryUsageLevel;
+
+    public void setCpuUsageLevel(@UsageLevel int usageLevel) {
+        this.mCpuUsageLevel = usageLevel;
+    }
+
+    public void setMemoryUsageLevel(@UsageLevel int usageLevel) {
+        this.mMemoryUsageLevel = usageLevel;
+    }
+
+    public @UsageLevel int getCpuUsageLevel() {
+        return this.mCpuUsageLevel;
+    }
+
+    public @UsageLevel int getMemoryUsageLevel() {
+        return this.mMemoryUsageLevel;
+    }
+}
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
index 4fe9ffe..931a557 100644
--- a/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/databroker/DataBrokerControllerUnitTest.java
@@ -19,25 +19,28 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 
 import com.android.car.telemetry.TelemetryProto;
+import com.android.car.telemetry.systemmonitor.SystemMonitor;
+import com.android.car.telemetry.systemmonitor.SystemMonitorEvent;
 
-import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
+import org.mockito.junit.MockitoJUnitRunner;
 
-
+@RunWith(MockitoJUnitRunner.class)
 public class DataBrokerControllerUnitTest {
-    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
 
     @Mock private DataBroker mMockDataBroker;
 
+    @Mock private SystemMonitor mMockSystemMonitor;
+
     @Captor ArgumentCaptor<TelemetryProto.MetricsConfig> mConfigCaptor;
 
     @Captor ArgumentCaptor<Integer> mPriorityCaptor;
@@ -80,4 +83,74 @@
         verify(mMockDataBroker).setOnScriptFinishedCallback(
                 any(DataBrokerController.ScriptFinishedCallback.class));
     }
+
+    @Test
+    public void testOnSystemEvent_setDataBrokerPriorityCorrectlyForHighCpuUsage() {
+        SystemMonitorEvent highCpuEvent = new SystemMonitorEvent();
+        highCpuEvent.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_HI);
+        highCpuEvent.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+
+        mController.onSystemMonitorEvent(highCpuEvent);
+
+        verify(mMockDataBroker, atLeastOnce())
+            .setTaskExecutionPriority(mPriorityCaptor.capture());
+        assertThat(mPriorityCaptor.getValue())
+            .isEqualTo(DataBrokerController.TASK_PRIORITY_HI);
+    }
+
+    @Test
+    public void testOnSystemEvent_setDataBrokerPriorityCorrectlyForHighMemUsage() {
+        SystemMonitorEvent highMemEvent = new SystemMonitorEvent();
+        highMemEvent.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+        highMemEvent.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_HI);
+
+        mController.onSystemMonitorEvent(highMemEvent);
+
+        verify(mMockDataBroker, atLeastOnce())
+            .setTaskExecutionPriority(mPriorityCaptor.capture());
+        assertThat(mPriorityCaptor.getValue())
+            .isEqualTo(DataBrokerController.TASK_PRIORITY_HI);
+    }
+
+    @Test
+    public void testOnSystemEvent_setDataBrokerPriorityCorrectlyForMedCpuUsage() {
+        SystemMonitorEvent medCpuEvent = new SystemMonitorEvent();
+        medCpuEvent.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_MED);
+        medCpuEvent.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+
+        mController.onSystemMonitorEvent(medCpuEvent);
+
+        verify(mMockDataBroker, atLeastOnce())
+            .setTaskExecutionPriority(mPriorityCaptor.capture());
+        assertThat(mPriorityCaptor.getValue())
+            .isEqualTo(DataBrokerController.TASK_PRIORITY_MED);
+    }
+
+    @Test
+    public void testOnSystemEvent_setDataBrokerPriorityCorrectlyForMedMemUsage() {
+        SystemMonitorEvent medMemEvent = new SystemMonitorEvent();
+        medMemEvent.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+        medMemEvent.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_MED);
+
+        mController.onSystemMonitorEvent(medMemEvent);
+
+        verify(mMockDataBroker, atLeastOnce())
+            .setTaskExecutionPriority(mPriorityCaptor.capture());
+        assertThat(mPriorityCaptor.getValue())
+            .isEqualTo(DataBrokerController.TASK_PRIORITY_MED);
+    }
+
+    @Test
+    public void testOnSystemEvent_setDataBrokerPriorityCorrectlyForLowUsage() {
+        SystemMonitorEvent lowUsageEvent = new SystemMonitorEvent();
+        lowUsageEvent.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+        lowUsageEvent.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_LOW);
+
+        mController.onSystemMonitorEvent(lowUsageEvent);
+
+        verify(mMockDataBroker, atLeastOnce())
+            .setTaskExecutionPriority(mPriorityCaptor.capture());
+        assertThat(mPriorityCaptor.getValue())
+            .isEqualTo(DataBrokerController.TASK_PRIORITY_LOW);
+    }
 }
diff --git a/tests/carservice_unit_test/src/com/android/car/telemetry/systemmonitor/SystemMonitorEventUnitTest.java b/tests/carservice_unit_test/src/com/android/car/telemetry/systemmonitor/SystemMonitorEventUnitTest.java
new file mode 100644
index 0000000..46b9992
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/telemetry/systemmonitor/SystemMonitorEventUnitTest.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.systemmonitor;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SystemMonitorEventUnitTest {
+
+    @Test
+    public void testCpuUsageLevelGetterSetter_correctlyGetSetCpuUsageLevel() {
+        SystemMonitorEvent event = new SystemMonitorEvent();
+        event.setCpuUsageLevel(SystemMonitorEvent.USAGE_LEVEL_HI);
+
+        assertThat(event.getCpuUsageLevel())
+            .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_HI);
+    }
+
+    @Test
+    public void testMemUsageLevelGetterSetter_correctlyGetSetMemUsageLevel() {
+        SystemMonitorEvent event = new SystemMonitorEvent();
+        event.setMemoryUsageLevel(SystemMonitorEvent.USAGE_LEVEL_MED);
+
+        assertThat(event.getMemoryUsageLevel())
+            .isEqualTo(SystemMonitorEvent.USAGE_LEVEL_MED);
+    }
+}