[Re-land] Remove iorap framework codes
This reverts commit 2f393cdbce9878ede68b7d4c32ddc404727c3532.
- It's decided to remove iorap from Android.
- This CL removes iorap framework codes.
- Removing iorap daemon and git repo will follow.
Bug: 211461392
Test: build okay
Change-Id: Ie1bebf1dfdce8b5db59c4e5a685c8f1afb46e266
Merged-In: Ie1bebf1dfdce8b5db59c4e5a685c8f1afb46e266
(cherry picked from commit 7ee89676b975e17e44de19bfc63173bdb9614d3b)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 58a3bb4..1e8ab05 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6907,10 +6907,6 @@
android:resource="@xml/autofill_compat_accessibility_service" />
</service>
- <service android:name="com.google.android.startop.iorap.IorapForwardingService$IorapdJobServiceProxy"
- android:permission="android.permission.BIND_JOB_SERVICE" >
- </service>
-
<service android:name="com.android.server.blob.BlobStoreIdleJobService"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
diff --git a/services/Android.bp b/services/Android.bp
index 2e4405f..c9d7ca2 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -106,7 +106,6 @@
":services.selectiontoolbar-sources",
":services.smartspace-sources",
":services.speech-sources",
- ":services.startop.iorap-sources",
":services.systemcaptions-sources",
":services.translation-sources",
":services.texttospeech-sources",
@@ -163,7 +162,6 @@
"services.selectiontoolbar",
"services.smartspace",
"services.speech",
- "services.startop",
"services.systemcaptions",
"services.translation",
"services.texttospeech",
@@ -216,7 +214,6 @@
" --hide-annotation android.annotation.Hide" +
" --hide InternalClasses" + // com.android.* classes are okay in this interface
// TODO: remove the --hide options below
- " --hide-package com.google.android.startop.iorap" +
" --hide DeprecationMismatch" +
" --hide HiddenTypedefConstant",
visibility: ["//frameworks/base:__subpackages__"],
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5098abe..1360fad 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -214,8 +214,6 @@
import dalvik.system.VMRuntime;
-import com.google.android.startop.iorap.IorapForwardingService;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -1642,10 +1640,6 @@
mSystemServiceManager.startService(PinnerService.class);
t.traceEnd();
- t.traceBegin("IorapForwardingService");
- mSystemServiceManager.startService(IorapForwardingService.class);
- t.traceEnd();
-
if (Build.IS_DEBUGGABLE && ProfcollectForwardingService.enabled()) {
t.traceBegin("ProfcollectForwardingService");
mSystemServiceManager.startService(ProfcollectForwardingService.class);
diff --git a/services/startop/Android.bp b/services/startop/Android.bp
deleted file mode 100644
index c56c463..0000000
--- a/services/startop/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-MIT
- // SPDX-license-identifier-Unicode-DFS
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library_static {
- name: "services.startop",
- defaults: ["platform_service_defaults"],
-
- static_libs: [
- // frameworks/base/startop/iorap
- "services.startop.iorap",
- ],
-}
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
deleted file mode 100644
index 4fdf34c..0000000
--- a/startop/iorap/Android.bp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2018 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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
- name: "services.startop.iorap-javasources",
- srcs: ["src/**/*.java"],
- path: "src",
- visibility: ["//visibility:private"],
-}
-
-filegroup {
- name: "services.startop.iorap-sources",
- srcs: [
- ":services.startop.iorap-javasources",
- ":iorap-aidl",
- ],
- visibility: ["//frameworks/base/services:__subpackages__"],
-}
-
-java_library_static {
- name: "services.startop.iorap",
- srcs: [":services.startop.iorap-sources"],
- libs: ["services.core"],
-}
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
deleted file mode 100644
index 8c9d4df..0000000
--- a/startop/iorap/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libiorap-java-tests"
- }
- ],
- "imports": [
- {
- "path": "system/iorap"
- }
- ]
-}
diff --git a/startop/iorap/functional_tests/Android.bp b/startop/iorap/functional_tests/Android.bp
deleted file mode 100644
index 43c6155..0000000
--- a/startop/iorap/functional_tests/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "iorap-functional-tests",
- srcs: ["src/**/*.java"],
- data: [":iorap-functional-test-apps"],
- static_libs: [
- // Non-test dependencies
- // library under test
- "services.startop.iorap",
- // Test Dependencies
- // test android dependencies
- "platform-test-annotations",
- "androidx.test.rules",
- "androidx.test.ext.junit",
- "androidx.test.uiautomator_uiautomator",
- // test framework dependencies
- "truth-prebuilt",
- ],
- dxflags: ["--multi-dex"],
- test_suites: ["device-tests"],
- compile_multilib: "both",
- libs: [
- "android.test.base",
- "android.test.runner",
- ],
- certificate: "platform",
- platform_apis: true,
-}
diff --git a/startop/iorap/functional_tests/AndroidManifest.xml b/startop/iorap/functional_tests/AndroidManifest.xml
deleted file mode 100644
index 6bddc4a3..0000000
--- a/startop/iorap/functional_tests/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<!--suppress AndroidUnknownAttribute -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.startop.iorap.tests"
- android:sharedUserId="com.google.android.startop.iorap.tests.functional"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!--suppress AndroidDomInspection -->
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.google.android.startop.iorap.tests" />
-
- <!--
- 'debuggable=true' is required to properly load mockito jvmti dependencies,
- otherwise it gives the following error at runtime:
-
- Openjdkjvmti plugin was loaded on a non-debuggable Runtime.
- Plugin was loaded too late to change runtime state to DEBUGGABLE. -->
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-</manifest>
diff --git a/startop/iorap/functional_tests/AndroidTest.xml b/startop/iorap/functional_tests/AndroidTest.xml
deleted file mode 100644
index 31d4f6c..0000000
--- a/startop/iorap/functional_tests/AndroidTest.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<configuration description="Runs iorap-functional-tests.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-instrumentation" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="iorap-functional-tests.apk" />
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
- <target_preparer
- class="com.android.tradefed.targetprep.DeviceSetup">
-
- <!-- iorapd does not pick up the above changes until we restart it -->
- <option name="run-command" value="stop iorapd" />
-
- <!-- Clean up the existing iorap database. -->
- <option name="run-command" value="rm -r /data/misc/iorapd/*" />
- <option name="run-command" value="sleep 1" />
-
- <!-- Set system properties to enable perfetto tracing, readahead and detailed logging. -->
- <option name="run-command" value="setprop iorapd.perfetto.enable true" />
- <option name="run-command" value="setprop iorapd.readahead.enable true" />
- <option name="run-command" value="setprop iorapd.log.verbose true" />
-
- <option name="run-command" value="start iorapd" />
-
- <!-- give it some time to restart the service; otherwise the first unit test might fail -->
- <option name="run-command" value="sleep 1" />
- </target_preparer>
-
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="abort-on-push-failure" value="true" />
- <option name="push-file"
- key="iorap_test_app_v1.apk"
- value="/data/misc/iorapd/iorap_test_app_v1.apk" />
- <option name="push-file"
- key="iorap_test_app_v2.apk"
- value="/data/misc/iorapd/iorap_test_app_v2.apk" />
- <option name="push-file"
- key="iorap_test_app_v3.apk"
- value="/data/misc/iorapd/iorap_test_app_v3.apk" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.google.android.startop.iorap.tests" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <!-- test-timeout unit is ms, value = 30 min -->
- <option name="test-timeout" value="1800000" />
- </test>
-
-</configuration>
-
diff --git a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java
deleted file mode 100644
index 5352be6..0000000
--- a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * 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.
- */
-
-package com.google.android.startop.iorapd;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.concurrent.TimeUnit;
-import java.util.Date;
-import java.util.function.BooleanSupplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.List;
-import java.text.SimpleDateFormat;
-
-/**
- * Test for the work flow of iorap.
- *
- * <p> This test tests the function of iorap from:
- * perfetto collection -> compilation -> prefetching -> version update -> perfetto collection.
- */
-@RunWith(AndroidJUnit4.class)
-public class IorapWorkFlowTest {
- private static final String TAG = "IorapWorkFlowTest";
-
- private static final String TEST_APP_VERSION_ONE_PATH = "/data/misc/iorapd/iorap_test_app_v1.apk";
- private static final String TEST_APP_VERSION_TWO_PATH = "/data/misc/iorapd/iorap_test_app_v2.apk";
- private static final String TEST_APP_VERSION_THREE_PATH = "/data/misc/iorapd/iorap_test_app_v3.apk";
-
- private static final String DB_PATH = "/data/misc/iorapd/sqlite.db";
- private static final Duration TIMEOUT = Duration.ofSeconds(300L);
-
- private UiDevice mDevice;
-
- @Before
- public void setUp() throws Exception {
- // Initialize UiDevice instance
- mDevice = UiDevice.getInstance(getInstrumentation());
-
- // Start from the home screen
- mDevice.pressHome();
-
- // Wait for launcher
- final String launcherPackage = mDevice.getLauncherPackageName();
- assertThat(launcherPackage, notNullValue());
- mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIMEOUT.getSeconds());
- }
-
- @After
- public void tearDown() throws Exception {
- String packageName = "com.example.ioraptestapp";
- uninstallApk(packageName);
- }
-
- @Test (timeout = 300000)
- public void testNormalWorkFlow() throws Exception {
- assertThat(mDevice, notNullValue());
-
- // Install test app version one
- installApk(TEST_APP_VERSION_ONE_PATH);
- String packageName = "com.example.ioraptestapp";
- String activityName = "com.example.ioraptestapp.MainActivity";
-
- // Perfetto trace collection phase.
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/1L));
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/1L));
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/1L));
-
- // Trigger maintenance service for compilation.
- TimeUnit.SECONDS.sleep(5L);
- assertTrue(compile(packageName, activityName, /*version=*/1L));
-
- // Run app with prefetching
- assertTrue(startAppWithCompiledTrace(
- packageName, activityName, /*version=*/1L));
- }
-
- @Test (timeout = 300000)
- public void testUpdateApp() throws Exception {
- assertThat(mDevice, notNullValue());
-
- // Install test app version two,
- String packageName = "com.example.ioraptestapp";
- String activityName = "com.example.ioraptestapp.MainActivity";
- installApk(TEST_APP_VERSION_TWO_PATH);
-
- // Perfetto trace collection phase.
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/2L));
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/2L));
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/2L));
-
- // Trigger maintenance service for compilation.
- TimeUnit.SECONDS.sleep(5L);
- assertTrue(compile(packageName, activityName, /*version=*/2L));
-
- // Run app with prefetching
- assertTrue(startAppWithCompiledTrace(
- packageName, activityName, /*version=*/2L));
-
- // Update test app to version 3
- installApk(TEST_APP_VERSION_THREE_PATH);
-
- // Rerun app, should do pefetto tracing.
- assertTrue(startAppForPerfettoTrace(
- packageName, activityName, /*version=*/3L));
- }
-
- private static void installApk(String apkPath) throws Exception {
- // Disable the selinux to allow pm install apk in the dir.
- executeShellCommand("setenforce 0");
- executeShellCommand("pm install -r -d " + apkPath);
- executeShellCommand("setenforce 1");
-
- }
-
- private static void uninstallApk(String apkPath) throws Exception {
- executeShellCommand("pm uninstall " + apkPath);
- }
-
- /**
- * Starts the testing app to collect the perfetto trace.
- *
- * @param expectPerfettoTraceCount is the expected count of perfetto traces.
- */
- private boolean startAppForPerfettoTrace(
- String packageName, String activityName, long version)
- throws Exception {
- LogcatTimestamp timestamp = runAppOnce(packageName, activityName);
- return waitForPerfettoTraceSavedFromLogcat(
- packageName, activityName, version, timestamp);
- }
-
- private boolean startAppWithCompiledTrace(
- String packageName, String activityName, long version)
- throws Exception {
- LogcatTimestamp timestamp = runAppOnce(packageName, activityName);
- return waitForPrefetchingFromLogcat(
- packageName, activityName, version, timestamp);
- }
-
- private LogcatTimestamp runAppOnce(String packageName, String activityName) throws Exception {
- // Close the specified app if it's open
- closeApp(packageName);
- LogcatTimestamp timestamp = new LogcatTimestamp();
- // Launch the specified app
- startApp(packageName, activityName);
- // Wait for the app to appear
- mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), TIMEOUT.getSeconds());
- return timestamp;
- }
-
- // Invokes the maintenance to compile the perfetto traces to compiled trace.
- private boolean compile(
- String packageName, String activityName, long version) throws Exception {
- // The job id (283673059) is defined in class IorapForwardingService.
- executeShellCommandViaTmpFile("cmd jobscheduler run -f android 283673059");
- return waitForFileExistence(getCompiledTracePath(packageName, activityName, version));
- }
-
- private String getCompiledTracePath(
- String packageName, String activityName, long version) {
- return String.format(
- "/data/misc/iorapd/%s/%d/%s/compiled_traces/compiled_trace.pb",
- packageName, version, activityName);
- }
-
- /**
- * Starts the testing app.
- */
- private void startApp(String packageName, String activityName) throws Exception {
- executeShellCommandViaTmpFile(
- String.format("am start %s/%s", packageName, activityName));
- }
-
- /**
- * Closes the testing app.
- * <p> Keep trying to kill the process of the app until no process of the app package
- * appears.</p>
- */
- private void closeApp(String packageName) throws Exception {
- while (true) {
- String pid = executeShellCommand("pidof " + packageName);
- if (pid.isEmpty()) {
- Log.i(TAG, "Closed app " + packageName);
- return;
- }
- executeShellCommand("kill -9 " + pid);
- TimeUnit.SECONDS.sleep(1L);
- }
- }
-
- /** Waits for a file to appear. */
- private boolean waitForFileExistence(String fileName) throws Exception {
- return retryWithTimeout(TIMEOUT, () -> {
- try {
- String fileExists = executeShellCommandViaTmpFile(
- String.format("test -f %s; echo $?", fileName));
- Log.i(TAG, fileName + " existence is " + fileExists);
- return fileExists.trim().equals("0");
- } catch (Exception e) {
- Log.i(TAG, e.getMessage());
- return false;
- }
- });
- }
-
- /** Waits for the perfetto trace saved message from logcat. */
- private boolean waitForPerfettoTraceSavedFromLogcat(
- String packageName, String activityName, long version, LogcatTimestamp timestamp)
- throws Exception {
- Pattern p = Pattern.compile(".*"
- + getPerfettoTraceSavedIndicator(packageName, activityName, version)
- + "(.*[.]perfetto_trace[.]pb)\n.*", Pattern.DOTALL);
-
- return retryWithTimeout(TIMEOUT, () -> {
- try {
- String log = timestamp.getLogcatAfter();
- Matcher m = p.matcher(log);
- Log.d(TAG, "Tries to find perfetto trace...");
- if (!m.matches()) {
- Log.i(TAG, "Cannot find perfetto trace saved in log.");
- return false;
- }
- String filePath = m.group(1);
- Log.i(TAG, "Perfetto trace is saved to " + filePath);
- return true;
- } catch(Exception e) {
- Log.e(TAG, e.getMessage());
- return false;
- }
- });
- }
-
- private String getPerfettoTraceSavedIndicator(
- String packageName, String activityName, long version) {
- return String.format(
- "Perfetto TraceBuffer saved to file: /data/misc/iorapd/%s/%d/%s/raw_traces/",
- packageName, version, activityName);
- }
-
- /**
- * Waits for the prefetching log in the logcat.
- *
- * <p> When prefetching works, the perfetto traces should not be collected. </p>
- */
- private boolean waitForPrefetchingFromLogcat(
- String packageName, String activityName, long version, LogcatTimestamp timestamp)
- throws Exception {
- Pattern p = Pattern.compile(
- ".*" + getReadaheadIndicator(packageName, activityName, version) +
- ".*Total File Paths=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n"
- + ".*Total Entries=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n"
- + ".*Total Bytes=(\\d+) \\(good: (\\d+[.]?\\d*)%\\).*",
- Pattern.DOTALL);
-
- return retryWithTimeout(TIMEOUT, () -> {
- try {
- String log = timestamp.getLogcatAfter();
- Matcher m = p.matcher(log);
- if (!m.matches()) {
- Log.i(TAG, "Cannot find readahead log.");
- return false;
- }
-
- int totalFilePath = Integer.parseInt(m.group(1));
- float totalFilePathGoodRate = Float.parseFloat(m.group(2)) / 100;
- int totalEntries = Integer.parseInt(m.group(3));
- float totalEntriesGoodRate = Float.parseFloat(m.group(4)) / 100;
- int totalBytes = Integer.parseInt(m.group(5));
- float totalBytesGoodRate = Float.parseFloat(m.group(6)) / 100;
-
- Log.i(TAG, String.format(
- "totalFilePath: %d (good %.2f) totalEntries: %d (good %.2f) totalBytes: %d (good %.2f)",
- totalFilePath, totalFilePathGoodRate, totalEntries, totalEntriesGoodRate, totalBytes,
- totalBytesGoodRate));
-
- return totalFilePath > 0 &&
- totalEntries > 0 &&
- totalBytes > 0 &&
- totalFilePathGoodRate > 0.5 &&
- totalEntriesGoodRate > 0.5 &&
- totalBytesGoodRate > 0.5;
- } catch(Exception e) {
- return false;
- }
- });
- }
-
- private static String getReadaheadIndicator(
- String packageName, String activityName, long version) {
- return String.format(
- "Description = /data/misc/iorapd/%s/%d/%s/compiled_traces/compiled_trace.pb",
- packageName, version, activityName);
- }
-
- /** Retry until timeout. */
- private boolean retryWithTimeout(Duration timeout, BooleanSupplier supplier) throws Exception {
- long totalSleepTimeSeconds = 0L;
- long sleepIntervalSeconds = 2L;
- while (true) {
- if (supplier.getAsBoolean()) {
- return true;
- }
- TimeUnit.SECONDS.sleep(sleepIntervalSeconds);
- totalSleepTimeSeconds += sleepIntervalSeconds;
- if (totalSleepTimeSeconds > timeout.getSeconds()) {
- return false;
- }
- }
- }
-
- /**
- * Executes command in adb shell via a tmp file.
- *
- * <p> This should be run as root.</p>
- */
- private static String executeShellCommandViaTmpFile(String cmd) throws Exception {
- Log.i(TAG, "Execute via tmp file: " + cmd);
- Path tmp = null;
- try {
- tmp = Files.createTempFile(/*prefix=*/null, /*suffix=*/".sh");
- Files.write(tmp, cmd.getBytes(StandardCharsets.UTF_8));
- tmp.toFile().setExecutable(true);
- return UiDevice.getInstance(
- InstrumentationRegistry.getInstrumentation()).
- executeShellCommand(tmp.toString());
- } finally {
- if (tmp != null) {
- Files.delete(tmp);
- }
- }
- }
-
- /**
- * Executes command in adb shell.
- *
- * <p> This should be run as root.</p>
- */
- private static String executeShellCommand(String cmd) throws Exception {
- Log.i(TAG, "Execute: " + cmd);
- return UiDevice.getInstance(
- InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
- }
-
- static class LogcatTimestamp {
- private String epochTime;
-
- public LogcatTimestamp() throws Exception{
- long currentTimeMillis = System.currentTimeMillis();
- epochTime = String.format(
- "%d.%03d", currentTimeMillis/1000, currentTimeMillis%1000);
- Log.i(TAG, "Current logcat timestamp is " + epochTime);
- }
-
- // For example, 1585264100.000
- public String getEpochTime() {
- return epochTime;
- }
-
- // Gets the logcat after this epoch time.
- public String getLogcatAfter() throws Exception {
- return executeShellCommandViaTmpFile(
- "logcat -v epoch -t '" + epochTime + "'");
- }
- }
-}
-
diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java
deleted file mode 100644
index 1d38f4c..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/ActivityHintEvent.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Provide a hint to iorapd that an activity has transitioned state.<br /><br />
- *
- * Knowledge of when an activity starts/stops can be used by iorapd to increase system
- * performance (e.g. by launching perfetto tracing to record an io profile, or by
- * playing back an ioprofile via readahead) over the long run.<br /><br />
- *
- * /@see com.google.android.startop.iorap.IIorap#onActivityHintEvent<br /><br />
- *
- * Once an activity hint is in {@link #TYPE_STARTED} it must transition to another type.
- * All other states could be terminal, see below: <br /><br />
- *
- * <pre>
- *
- * ┌──────────────────────────────────────┐
- * │ ▼
- * ┌─────────┐ ╔════════════════╗ ╔═══════════╗
- * ──▶ │ STARTED │ ──▶ ║ COMPLETED ║ ──▶ ║ CANCELLED ║
- * └─────────┘ ╚════════════════╝ ╚═══════════╝
- * │
- * │
- * ▼
- * ╔════════════════╗
- * ║ POST_COMPLETED ║
- * ╚════════════════╝
- *
- * </pre> <!-- system/iorap/docs/binder/ActivityHint.dot -->
- *
- * @hide
- */
-public class ActivityHintEvent implements Parcelable {
-
- public static final int TYPE_STARTED = 0;
- public static final int TYPE_CANCELLED = 1;
- public static final int TYPE_COMPLETED = 2;
- public static final int TYPE_POST_COMPLETED = 3;
- private static final int TYPE_MAX = TYPE_POST_COMPLETED;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_STARTED,
- TYPE_CANCELLED,
- TYPE_COMPLETED,
- TYPE_POST_COMPLETED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
- public final ActivityInfo activityInfo;
-
- public ActivityHintEvent(@Type int type, ActivityInfo activityInfo) {
- this.type = type;
- this.activityInfo = activityInfo;
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- Objects.requireNonNull(activityInfo, "activityInfo");
- }
-
- @Override
- public String toString() {
- return String.format("{type: %d, activityInfo: %s}", type, activityInfo);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof ActivityHintEvent) {
- return equals((ActivityHintEvent) other);
- }
- return false;
- }
-
- private boolean equals(ActivityHintEvent other) {
- return type == other.type &&
- Objects.equals(activityInfo, other.activityInfo);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- activityInfo.writeToParcel(out, flags);
- }
-
- private ActivityHintEvent(Parcel in) {
- this.type = in.readInt();
- this.activityInfo = ActivityInfo.CREATOR.createFromParcel(in);
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<ActivityHintEvent> CREATOR
- = new Parcelable.Creator<ActivityHintEvent>() {
- public ActivityHintEvent createFromParcel(Parcel in) {
- return new ActivityHintEvent(in);
- }
-
- public ActivityHintEvent[] newArray(int size) {
- return new ActivityHintEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java b/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java
deleted file mode 100644
index f47a42c..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/ActivityInfo.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import java.util.Objects;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-/**
- * Provide minimal information for launched activities to iorap.<br /><br />
- *
- * This uniquely identifies a system-wide activity by providing the {@link #packageName} and
- * {@link #activityName}.
- *
- * @see ActivityHintEvent
- * @see AppIntentEvent
- *
- * @hide
- */
-public class ActivityInfo implements Parcelable {
-
- /** The name of the package, for example {@code com.android.calculator}. */
- public final String packageName;
- /** The name of the activity, for example {@code .activities.activity.MainActivity} */
- public final String activityName;
-
- public ActivityInfo(String packageName, String activityName) {
- this.packageName = packageName;
- this.activityName = activityName;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- Objects.requireNonNull(packageName, "packageName");
- Objects.requireNonNull(activityName, "activityName");
- }
-
- @Override
- public String toString() {
- return String.format("{packageName: %s, activityName: %s}", packageName, activityName);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof ActivityInfo) {
- return equals((ActivityInfo) other);
- }
- return false;
- }
-
- private boolean equals(ActivityInfo other) {
- return Objects.equals(packageName, other.packageName) &&
- Objects.equals(activityName, other.activityName);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(packageName);
- out.writeString(activityName);
- }
-
- private ActivityInfo(Parcel in) {
- packageName = in.readString();
- activityName = in.readString();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<ActivityInfo> CREATOR
- = new Parcelable.Creator<ActivityInfo>() {
- public ActivityInfo createFromParcel(Parcel in) {
- return new ActivityInfo(in);
- }
-
- public ActivityInfo[] newArray(int size) {
- return new ActivityInfo[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java
deleted file mode 100644
index 1cd37b5..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/AppIntentEvent.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Notifications for iorapd specifying when a system-wide intent defaults change.<br /><br />
- *
- * Intent defaults provide a mechanism for an app to register itself as an automatic handler.
- * For example the camera app might be registered as the default handler for
- * {@link android.provider.MediaStore#INTENT_ACTION_STILL_IMAGE_CAMERA} intent. Subsequently,
- * if an arbitrary other app requests for a still image camera photo to be taken, the system
- * will launch the respective default camera app to be launched to handle that request.<br /><br />
- *
- * In some cases iorapd might need to know default intents, e.g. for boot-time pinning of
- * applications that resolve from the default intent. If the application would now be resolved
- * differently, iorapd would unpin the old application and pin the new application.<br /><br />
- *
- * @hide
- */
-public class AppIntentEvent implements Parcelable {
-
- /** @see android.content.Intent#CATEGORY_DEFAULT */
- public static final int TYPE_DEFAULT_INTENT_CHANGED = 0;
- private static final int TYPE_MAX = 0;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_DEFAULT_INTENT_CHANGED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
-
- public final ActivityInfo oldActivityInfo;
- public final ActivityInfo newActivityInfo;
-
- // TODO: Probably need the corresponding action here as well.
-
- public static AppIntentEvent createDefaultIntentChanged(ActivityInfo oldActivityInfo,
- ActivityInfo newActivityInfo) {
- return new AppIntentEvent(TYPE_DEFAULT_INTENT_CHANGED, oldActivityInfo,
- newActivityInfo);
- }
-
- private AppIntentEvent(@Type int type, ActivityInfo oldActivityInfo,
- ActivityInfo newActivityInfo) {
- this.type = type;
- this.oldActivityInfo = oldActivityInfo;
- this.newActivityInfo = newActivityInfo;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- Objects.requireNonNull(oldActivityInfo, "oldActivityInfo");
- Objects.requireNonNull(oldActivityInfo, "newActivityInfo");
- }
-
- @Override
- public String toString() {
- return String.format("{oldActivityInfo: %s, newActivityInfo: %s}", oldActivityInfo,
- newActivityInfo);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof AppIntentEvent) {
- return equals((AppIntentEvent) other);
- }
- return false;
- }
-
- private boolean equals(AppIntentEvent other) {
- return type == other.type &&
- Objects.equals(oldActivityInfo, other.oldActivityInfo) &&
- Objects.equals(newActivityInfo, other.newActivityInfo);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- oldActivityInfo.writeToParcel(out, flags);
- newActivityInfo.writeToParcel(out, flags);
- }
-
- private AppIntentEvent(Parcel in) {
- this.type = in.readInt();
- this.oldActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
- this.newActivityInfo = ActivityInfo.CREATOR.createFromParcel(in);
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<AppIntentEvent> CREATOR
- = new Parcelable.Creator<AppIntentEvent>() {
- public AppIntentEvent createFromParcel(Parcel in) {
- return new AppIntentEvent(in);
- }
-
- public AppIntentEvent[] newArray(int size) {
- return new AppIntentEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
deleted file mode 100644
index 8263e0a..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.annotation.LongDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.server.wm.ActivityMetricsLaunchObserver;
-import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
-import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br />
- *
- * Knowledge of when an activity starts/stops can be used by iorapd to increase system
- * performance (e.g. by launching perfetto tracing to record an io profile, or by
- * playing back an ioprofile via readahead) over the long run.<br /><br />
- *
- * /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br />
- * @see com.android.server.wm.ActivityMetricsLaunchObserver
- * ActivityMetricsLaunchObserver for the possible event states.
- * @hide
- */
-public abstract class AppLaunchEvent implements Parcelable {
- @LongDef
- @Retention(RetentionPolicy.SOURCE)
- public @interface SequenceId {}
-
- public final @SequenceId
- long sequenceId;
-
- protected AppLaunchEvent(@SequenceId long sequenceId) {
- this.sequenceId = sequenceId;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof AppLaunchEvent) {
- return equals((AppLaunchEvent) other);
- }
- return false;
- }
-
- protected boolean equals(AppLaunchEvent other) {
- return sequenceId == other.sequenceId;
- }
-
-
- @Override
- public String toString() {
- return getClass().getSimpleName() +
- "{" + "sequenceId=" + Long.toString(sequenceId) +
- toStringBody() + "}";
- }
-
- protected String toStringBody() { return ""; };
-
- // List of possible variants:
-
- public static final class IntentStarted extends AppLaunchEvent {
- @NonNull
- public final Intent intent;
- public final long timestampNs;
-
- public IntentStarted(@SequenceId long sequenceId,
- Intent intent,
- long timestampNs) {
- super(sequenceId);
- this.intent = intent;
- this.timestampNs = timestampNs;
-
- Objects.requireNonNull(intent, "intent");
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof IntentStarted) {
- return intent.equals(((IntentStarted)other).intent) &&
- timestampNs == ((IntentStarted)other).timestampNs &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return ", intent=" + intent.toString() +
- " , timestampNs=" + Long.toString(timestampNs);
- }
-
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- IntentProtoParcelable.write(p, intent, flags);
- p.writeLong(timestampNs);
- }
-
- IntentStarted(Parcel p) {
- super(p);
- intent = IntentProtoParcelable.create(p);
- timestampNs = p.readLong();
- }
- }
-
- public static final class IntentFailed extends AppLaunchEvent {
- public IntentFailed(@SequenceId long sequenceId) {
- super(sequenceId);
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof IntentFailed) {
- return super.equals(other);
- }
- return false;
- }
-
- IntentFailed(Parcel p) {
- super(p);
- }
- }
-
- public static abstract class BaseWithActivityRecordData extends AppLaunchEvent {
- public final @NonNull
- @ActivityRecordProto byte[] activityRecordSnapshot;
-
- protected BaseWithActivityRecordData(@SequenceId long sequenceId,
- @NonNull @ActivityRecordProto byte[] snapshot) {
- super(sequenceId);
- activityRecordSnapshot = snapshot;
-
- Objects.requireNonNull(snapshot, "snapshot");
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof BaseWithActivityRecordData) {
- return (Arrays.equals(activityRecordSnapshot,
- ((BaseWithActivityRecordData)other).activityRecordSnapshot)) &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return ", " + new String(activityRecordSnapshot);
- }
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
- }
-
- BaseWithActivityRecordData(Parcel p) {
- super(p);
- activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
- }
- }
-
- public static final class ActivityLaunched extends BaseWithActivityRecordData {
- public final @ActivityMetricsLaunchObserver.Temperature
- int temperature;
-
- public ActivityLaunched(@SequenceId long sequenceId,
- @NonNull @ActivityRecordProto byte[] snapshot,
- @ActivityMetricsLaunchObserver.Temperature int temperature) {
- super(sequenceId, snapshot);
- this.temperature = temperature;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof ActivityLaunched) {
- return temperature == ((ActivityLaunched)other).temperature &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return super.toStringBody() + ", temperature=" + Integer.toString(temperature);
- }
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- p.writeInt(temperature);
- }
-
- ActivityLaunched(Parcel p) {
- super(p);
- temperature = p.readInt();
- }
- }
-
- public static final class ActivityLaunchFinished extends BaseWithActivityRecordData {
- public final long timestampNs;
-
- public ActivityLaunchFinished(@SequenceId long sequenceId,
- @NonNull @ActivityRecordProto byte[] snapshot,
- long timestampNs) {
- super(sequenceId, snapshot);
- this.timestampNs = timestampNs;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof ActivityLaunchFinished) {
- return timestampNs == ((ActivityLaunchFinished)other).timestampNs &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return super.toStringBody() + ", timestampNs=" + Long.toString(timestampNs);
- }
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- p.writeLong(timestampNs);
- }
-
- ActivityLaunchFinished(Parcel p) {
- super(p);
- timestampNs = p.readLong();
- }
- }
-
- public static class ActivityLaunchCancelled extends AppLaunchEvent {
- public final @Nullable @ActivityRecordProto byte[] activityRecordSnapshot;
-
- public ActivityLaunchCancelled(@SequenceId long sequenceId,
- @Nullable @ActivityRecordProto byte[] snapshot) {
- super(sequenceId);
- activityRecordSnapshot = snapshot;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof ActivityLaunchCancelled) {
- return Arrays.equals(activityRecordSnapshot,
- ((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return super.toStringBody() + ", " + new String(activityRecordSnapshot);
- }
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- if (activityRecordSnapshot != null) {
- p.writeBoolean(true);
- ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
- } else {
- p.writeBoolean(false);
- }
- }
-
- ActivityLaunchCancelled(Parcel p) {
- super(p);
- if (p.readBoolean()) {
- activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
- } else {
- activityRecordSnapshot = null;
- }
- }
- }
-
- public static final class ReportFullyDrawn extends BaseWithActivityRecordData {
- public final long timestampNs;
-
- public ReportFullyDrawn(@SequenceId long sequenceId,
- @NonNull @ActivityRecordProto byte[] snapshot,
- long timestampNs) {
- super(sequenceId, snapshot);
- this.timestampNs = timestampNs;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other instanceof ReportFullyDrawn) {
- return timestampNs == ((ReportFullyDrawn)other).timestampNs &&
- super.equals(other);
- }
- return false;
- }
-
- @Override
- protected String toStringBody() {
- return super.toStringBody() + ", timestampNs=" + Long.toString(timestampNs);
- }
-
- @Override
- protected void writeToParcelImpl(Parcel p, int flags) {
- super.writeToParcelImpl(p, flags);
- p.writeLong(timestampNs);
- }
-
- ReportFullyDrawn(Parcel p) {
- super(p);
- timestampNs = p.readLong();
- }
- }
-
- @Override
- public @ContentsFlags int describeContents() { return 0; }
-
- @Override
- public void writeToParcel(Parcel p, @WriteFlags int flags) {
- p.writeInt(getTypeIndex());
-
- writeToParcelImpl(p, flags);
- }
-
-
- public static Creator<AppLaunchEvent> CREATOR =
- new Creator<AppLaunchEvent>() {
- @Override
- public AppLaunchEvent createFromParcel(Parcel source) {
- int typeIndex = source.readInt();
-
- Class<?> kls = getClassFromTypeIndex(typeIndex);
- if (kls == null) {
- throw new IllegalArgumentException("Invalid type index: " + typeIndex);
- }
-
- try {
- return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source);
- } catch (InstantiationException e) {
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- throw new AssertionError(e);
- } catch (InvocationTargetException e) {
- throw new AssertionError(e);
- } catch (NoSuchMethodException e) {
- throw new AssertionError(e);
- }
- }
-
- @Override
- public AppLaunchEvent[] newArray(int size) {
- return new AppLaunchEvent[0];
- }
- };
-
- protected void writeToParcelImpl(Parcel p, int flags) {
- p.writeLong(sequenceId);
- }
-
- protected AppLaunchEvent(Parcel p) {
- sequenceId = p.readLong();
- }
-
- private int getTypeIndex() {
- for (int i = 0; i < sTypes.length; ++i) {
- if (sTypes[i].equals(this.getClass())) {
- return i;
- }
- }
- throw new AssertionError("sTypes did not include this type: " + this.getClass());
- }
-
- private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) {
- if (typeIndex >= 0 && typeIndex < sTypes.length) {
- return sTypes[typeIndex];
- }
- return null;
- }
-
- // Index position matters: It is used to encode the specific type in parceling.
- // Keep up-to-date with C++ side.
- private static Class<?>[] sTypes = new Class[] {
- IntentStarted.class,
- IntentFailed.class,
- ActivityLaunched.class,
- ActivityLaunchFinished.class,
- ActivityLaunchCancelled.class,
- ReportFullyDrawn.class,
- };
-
- public static class ActivityRecordProtoParcelable {
- public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot,
- int flags) {
- p.writeByteArray(activityRecordSnapshot);
- }
-
- public static @ActivityRecordProto byte[] create(Parcel p) {
- byte[] data = p.createByteArray();
-
- return data;
- }
- }
-
- public static class IntentProtoParcelable {
- private static final int INTENT_PROTO_CHUNK_SIZE = 1024;
-
- public static void write(Parcel p, @NonNull Intent intent, int flags) {
- // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream,
- // so create a new one every time.
- final ProtoOutputStream protoOutputStream =
- new ProtoOutputStream(INTENT_PROTO_CHUNK_SIZE);
- // Write this data out as the top-most IntentProto (i.e. it is not a sub-object).
- intent.dumpDebug(protoOutputStream);
- final byte[] bytes = protoOutputStream.getBytes();
-
- p.writeByteArray(bytes);
- }
-
- // TODO: Should be mockable for testing?
- // We cannot deserialize in the platform because we don't have a 'readFromProto'
- // code.
- public static @NonNull Intent create(Parcel p) {
- // This will "read" the correct amount of data, but then we discard it.
- byte[] data = p.createByteArray();
-
- // Never called by real code in a platform, this binder API is implemented only in C++.
- return new Intent("<cannot deserialize IntentProto>");
- }
- }
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java b/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java
deleted file mode 100644
index 34aedd7..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/CheckHelpers.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-/**
- * Convenience short-hand to throw {@link IllegalAccessException} when the arguments
- * are out-of-range.
- */
-public class CheckHelpers {
- /** @throws IllegalAccessException if {@param type} is not in {@code [0..maxValue]} */
- public static void checkTypeInRange(int type, int maxValue) {
- if (type < 0) {
- throw new IllegalArgumentException(
- String.format("type must be non-negative (value=%d)", type));
- }
- if (type > maxValue) {
- throw new IllegalArgumentException(
- String.format("type out of range (value=%d, max=%d)", type, maxValue));
- }
- }
-
- /** @throws IllegalAccessException if {@param state} is not in {@code [0..maxValue]} */
- public static void checkStateInRange(int state, int maxValue) {
- if (state < 0) {
- throw new IllegalArgumentException(
- String.format("state must be non-negative (value=%d)", state));
- }
- if (state > maxValue) {
- throw new IllegalArgumentException(
- String.format("state out of range (value=%d, max=%d)", state, maxValue));
- }
- }
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java b/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java
deleted file mode 100644
index 72c5eaa..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.
- */
-
-package com.google.android.startop.iorap;
-
-import android.annotation.NonNull;
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Notifications for iorapd specifying when a package is updated by dexopt service.<br /><br />
- *
- * @hide
- */
-public class DexOptEvent implements Parcelable {
- public static final int TYPE_PACKAGE_UPDATE = 0;
- private static final int TYPE_MAX = 0;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_PACKAGE_UPDATE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
- public final String packageName;
-
- @NonNull
- public static DexOptEvent createPackageUpdate(String packageName) {
- return new DexOptEvent(TYPE_PACKAGE_UPDATE, packageName);
- }
-
- private DexOptEvent(@Type int type, String packageName) {
- this.type = type;
- this.packageName = packageName;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- Objects.requireNonNull(packageName, "packageName");
- }
-
- @Override
- public String toString() {
- return String.format("{DexOptEvent: packageName: %s}", packageName);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof DexOptEvent) {
- return equals((DexOptEvent) other);
- }
- return false;
- }
-
- private boolean equals(DexOptEvent other) {
- return packageName.equals(other.packageName);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- out.writeString(packageName);
- }
-
- private DexOptEvent(Parcel in) {
- this.type = in.readInt();
- this.packageName = in.readString();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<DexOptEvent> CREATOR
- = new Parcelable.Creator<DexOptEvent>() {
- public DexOptEvent createFromParcel(Parcel in) {
- return new DexOptEvent(in);
- }
-
- public DexOptEvent[] newArray(int size) {
- return new DexOptEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
deleted file mode 100644
index dcaff26..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * 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.
- */
-
-package com.google.android.startop.iorap;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Intent;
-import android.util.Log;
-
-import com.android.server.wm.ActivityMetricsLaunchObserver;
-
-import java.io.StringWriter;
-import java.io.PrintWriter;
-
-/**
- * A validator to check the correctness of event sequence during app startup.
- *
- * <p> A valid state transition of event sequence is shown as the following:
- *
- * <pre>
- *
- * +--------------------+
- * | |
- * | INIT |
- * | |
- * +--------------------+
- * |
- * |
- * ↓
- * +--------------------+
- * | |
- * +-------------------| INTENT_STARTED | ←--------------------------------+
- * | | | |
- * | +--------------------+ |
- * | | |
- * | | |
- * ↓ ↓ |
- * +--------------------+ +--------------------+ |
- * | | | | |
- * | INTENT_FAILED | | ACTIVITY_LAUNCHED |------------------+ |
- * | | | | | |
- * +--------------------+ +--------------------+ | |
- * | | | |
- * | ↓ ↓ |
- * | +--------------------+ +--------------------+ |
- * | | | | | |
- * +------------------ | ACTIVITY_FINISHED | | ACTIVITY_CANCELLED | |
- * | | | | | |
- * | +--------------------+ +--------------------+ |
- * | | | |
- * | | | |
- * | ↓ | |
- * | +--------------------+ | |
- * | | | | |
- * | | REPORT_FULLY_DRAWN | | |
- * | | | | |
- * | +--------------------+ | |
- * | | | |
- * | | | |
- * | ↓ | |
- * | +--------------------+ | |
- * | | | | |
- * +-----------------→ | END |←-----------------+ |
- * | | |
- * +--------------------+ |
- * | |
- * | |
- * | |
- * +---------------------------------------------
- *
- * <p> END is not a real state in implementation. All states that points to END directly
- * could transition to INTENT_STARTED.
- *
- * <p> If any bad transition happened, the state becomse UNKNOWN. The UNKNOWN state
- * could be accumulated, because during the UNKNOWN state more IntentStarted may
- * be triggered. To recover from UNKNOWN to INIT, all the accumualted IntentStarted
- * should termniate.
- *
- * <p> During UNKNOWN state, each IntentStarted increases the accumulation, and any of
- * IntentFailed, ActivityLaunchCancelled and ActivityFinished decreases the accumulation.
- * ReportFullyDrawn doesn't impact the accumulation.
- */
-public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
- static final String TAG = "EventSequenceValidator";
- /** $> adb shell 'setprop log.tag.EventSequenceValidator VERBOSE' */
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private State state = State.INIT;
- private long accIntentStartedEvents = 0;
-
- @Override
- public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("IntentStarted during UNKNOWN. " + intent);
- incAccIntentStartedEvents();
- return;
- }
-
- if (state != State.INIT &&
- state != State.INTENT_FAILED &&
- state != State.ACTIVITY_CANCELLED &&
- state != State.ACTIVITY_FINISHED &&
- state != State.REPORT_FULLY_DRAWN) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
- incAccIntentStartedEvents();
- incAccIntentStartedEvents();
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_STARTED));
- state = State.INTENT_STARTED;
- }
-
- @Override
- public void onIntentFailed() {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("onIntentFailed during UNKNOWN.");
- decAccIntentStartedEvents();
- return;
- }
- if (state != State.INTENT_STARTED) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
- incAccIntentStartedEvents();
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.INTENT_FAILED));
- state = State.INTENT_FAILED;
- }
-
- @Override
- public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
- @Temperature int temperature) {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("onActivityLaunched during UNKNOWN.");
- return;
- }
- if (state != State.INTENT_STARTED) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
- incAccIntentStartedEvents();
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
- state = State.ACTIVITY_LAUNCHED;
- }
-
- @Override
- public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("onActivityLaunchCancelled during UNKNOWN.");
- decAccIntentStartedEvents();
- return;
- }
- if (state != State.ACTIVITY_LAUNCHED) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
- incAccIntentStartedEvents();
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_CANCELLED));
- state = State.ACTIVITY_CANCELLED;
- }
-
- @Override
- public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
- long timestampNs) {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("onActivityLaunchFinished during UNKNOWN.");
- decAccIntentStartedEvents();
- return;
- }
-
- if (state != State.ACTIVITY_LAUNCHED) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
- incAccIntentStartedEvents();
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.ACTIVITY_FINISHED));
- state = State.ACTIVITY_FINISHED;
- }
-
- @Override
- public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
- long timestampNs) {
- if (state == State.UNKNOWN) {
- logWarningWithStackTrace("onReportFullyDrawn during UNKNOWN.");
- return;
- }
- if (state == State.INIT) {
- return;
- }
-
- if (state != State.ACTIVITY_FINISHED) {
- logWarningWithStackTrace(
- String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
- return;
- }
-
- Log.i(TAG, String.format("Transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
- state = State.REPORT_FULLY_DRAWN;
- }
-
- enum State {
- INIT,
- INTENT_STARTED,
- INTENT_FAILED,
- ACTIVITY_LAUNCHED,
- ACTIVITY_CANCELLED,
- ACTIVITY_FINISHED,
- REPORT_FULLY_DRAWN,
- UNKNOWN,
- }
-
- private void incAccIntentStartedEvents() {
- if (accIntentStartedEvents < 0) {
- throw new AssertionError("The number of unknowns cannot be negative");
- }
- if (accIntentStartedEvents == 0) {
- state = State.UNKNOWN;
- }
- ++accIntentStartedEvents;
- Log.i(TAG,
- String.format("inc AccIntentStartedEvents to %d", accIntentStartedEvents));
- }
-
- private void decAccIntentStartedEvents() {
- if (accIntentStartedEvents <= 0) {
- throw new AssertionError("The number of unknowns cannot be negative");
- }
- if(accIntentStartedEvents == 1) {
- state = State.INIT;
- }
- --accIntentStartedEvents;
- Log.i(TAG,
- String.format("dec AccIntentStartedEvents to %d", accIntentStartedEvents));
- }
-
- private void logWarningWithStackTrace(String log) {
- if (DEBUG) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- new Throwable("EventSequenceValidator#getStackTrace").printStackTrace(pw);
- Log.wtf(TAG, String.format("%s\n%s", log, sw));
- }
- }
-}
-
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
deleted file mode 100644
index 77046f2..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-// TODO: rename to com.android.server.startop.iorap
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.provider.DeviceConfig;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.IoThread;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.pm.BackgroundDexOptService;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.wm.ActivityMetricsLaunchObserver;
-import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
-import com.android.server.wm.ActivityTaskManagerInternal;
-
-import java.time.Duration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.BooleanSupplier;
-
-/**
- * System-server-local proxy into the {@code IIorap} native service.
- */
-public class IorapForwardingService extends SystemService {
-
- public static final String TAG = "IorapForwardingService";
- /** $> adb shell 'setprop log.tag.IorapForwardingService VERBOSE' */
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- /** $> adb shell 'setprop ro.iorapd.enable true' */
- private static boolean IS_ENABLED = SystemProperties.getBoolean("ro.iorapd.enable", true);
- /** $> adb shell 'setprop iorapd.forwarding_service.wtf_crash true' */
- private static boolean WTF_CRASH = SystemProperties.getBoolean(
- "iorapd.forwarding_service.wtf_crash", false);
- private static final Duration TIMEOUT = Duration.ofSeconds(600L);
-
- // "Unique" job ID from the service name. Also equal to 283673059.
- public static final int JOB_ID_IORAPD = encodeEnglishAlphabetStringIntoInt("iorapd");
- // Run every 24 hours.
- public static final long JOB_INTERVAL_MS = TimeUnit.HOURS.toMillis(24);
-
- private IIorap mIorapRemote;
- private final Object mLock = new Object();
- /** Handle onBinderDeath by periodically trying to reconnect. */
- private final Handler mHandler =
- new BinderConnectionHandler(IoThread.getHandler().getLooper());
-
- private volatile IorapdJobService mJobService; // Write-once (null -> non-null forever).
- private volatile static IorapForwardingService sSelfService; // Write once (null -> non-null).
-
-
- /**
- * Atomics set to true if the JobScheduler requests an abort.
- */
- private final AtomicBoolean mAbortIdleCompilation = new AtomicBoolean(false);
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public IorapForwardingService(Context context) {
- super(context);
-
- if (DEBUG) {
- Log.v(TAG, "IorapForwardingService (Context=" + context.toString() + ")");
- }
-
- if (sSelfService != null) {
- throw new AssertionError("only one service instance allowed");
- }
- sSelfService = this;
- }
-
- //<editor-fold desc="Providers">
- /*
- * Providers for external dependencies:
- * - These are marked as protected to allow tests to inject different values via mocks.
- */
-
- @VisibleForTesting
- protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() {
- ActivityTaskManagerInternal amtInternal =
- LocalServices.getService(ActivityTaskManagerInternal.class);
- ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
- amtInternal.getLaunchObserverRegistry();
- return launchObserverRegistry;
- }
-
- @VisibleForTesting
- protected IIorap provideIorapRemote() {
- IIorap iorap;
- try {
- iorap = IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
- } catch (ServiceManager.ServiceNotFoundException e) {
- Log.w(TAG, e.getMessage());
- return null;
- }
-
- try {
- iorap.asBinder().linkToDeath(provideDeathRecipient(), /*flags*/0);
- } catch (RemoteException e) {
- handleRemoteError(e);
- return null;
- }
-
- return iorap;
- }
-
- @VisibleForTesting
- protected DeathRecipient provideDeathRecipient() {
- return new DeathRecipient() {
- @Override
- public void binderDied() {
- Log.w(TAG, "iorapd has died");
- retryConnectToRemoteAndConfigure(/*attempts*/0);
-
- if (mJobService != null) {
- mJobService.onIorapdDisconnected();
- }
- }
- };
- }
-
- @VisibleForTesting
- protected boolean isIorapEnabled() {
- // These two mendel flags should match those in iorapd native process
- // system/iorapd/src/common/property.h
- boolean isTracingEnabled =
- getMendelFlag("iorap_perfetto_enable", "iorapd.perfetto.enable", false);
- boolean isReadAheadEnabled =
- getMendelFlag("iorap_readahead_enable", "iorapd.readahead.enable", false);
- // Same as the property in iorapd.rc -- disabling this will mean the 'iorapd' binder process
- // never comes up, so all binder connections will fail indefinitely.
- return IS_ENABLED && (isTracingEnabled || isReadAheadEnabled);
- }
-
- private boolean getMendelFlag(String mendelFlag, String sysProperty, boolean defaultValue) {
- // TODO(yawanng) use DeviceConfig to get mendel property.
- // DeviceConfig doesn't work and the reason is not clear.
- // Provider service is already up before IORapForwardService.
- String mendelProperty = "persist.device_config."
- + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT
- + "."
- + mendelFlag;
- return SystemProperties.getBoolean(mendelProperty,
- SystemProperties.getBoolean(sysProperty, defaultValue));
- }
-
- //</editor-fold>
-
- @Override
- public void onStart() {
- if (DEBUG) {
- Log.v(TAG, "onStart");
- }
-
- retryConnectToRemoteAndConfigure(/*attempts*/0);
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_BOOT_COMPLETED) {
- if (DEBUG) {
- Log.v(TAG, "onBootPhase(PHASE_BOOT_COMPLETED)");
- }
-
- if (isIorapEnabled()) {
- // Set up a recurring background job. This has to be done in a later phase since it
- // has a dependency the job scheduler.
- //
- // Doing this too early can result in a ServiceNotFoundException for 'jobservice'
- // or a null reference for #getSystemService(JobScheduler.class)
- mJobService = new IorapdJobService(getContext());
- }
- }
- }
-
- private class BinderConnectionHandler extends Handler {
- public BinderConnectionHandler(android.os.Looper looper) {
- super(looper);
- }
-
- public static final int MESSAGE_BINDER_CONNECT = 0;
-
- private int mAttempts = 0;
-
- @Override
- public void handleMessage(android.os.Message message) {
- switch (message.what) {
- case MESSAGE_BINDER_CONNECT:
- if (!retryConnectToRemoteAndConfigure(mAttempts)) {
- mAttempts++;
- } else {
- mAttempts = 0;
- }
- break;
- default:
- throw new AssertionError("Unknown message: " + message.toString());
- }
- }
- }
-
- /**
- * Handle iorapd shutdowns and crashes, by attempting to reconnect
- * until the service is reached again.
- *
- * <p>The first connection attempt is synchronous,
- * subsequent attempts are done by posting delayed tasks to the IoThread.</p>
- *
- * @return true if connection succeeded now, or false if it failed now [and needs to requeue].
- */
- private boolean retryConnectToRemoteAndConfigure(int attempts) {
- final int sleepTime = 1000; // ms
-
- if (DEBUG) {
- Log.v(TAG, "retryConnectToRemoteAndConfigure - attempt #" + attempts);
- }
-
- if (connectToRemoteAndConfigure()) {
- return true;
- }
-
- // Either 'iorapd' is stuck in a crash loop (ouch!!) or we manually
- // called 'adb shell stop iorapd' , which means this would loop until it comes back
- // up.
- //
- // TODO: it would be good to get nodified of 'adb shell stop iorapd' to avoid
- // printing this warning.
- if (DEBUG) {
- Log.v(TAG, "Failed to connect to iorapd, is it down? Delay for " + sleepTime);
- }
-
- // Use a handler instead of Thread#sleep to avoid backing up the binder thread
- // when this is called from the death recipient callback.
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(BinderConnectionHandler.MESSAGE_BINDER_CONNECT),
- sleepTime);
-
- return false;
-
- // Log.e(TAG, "Can't connect to iorapd - giving up after " + attempts + " attempts");
- }
-
- private boolean connectToRemoteAndConfigure() {
- synchronized (mLock) {
- // Synchronize against any concurrent calls to this via the DeathRecipient.
- return connectToRemoteAndConfigureLocked();
- }
- }
-
- private boolean connectToRemoteAndConfigureLocked() {
- if (!isIorapEnabled()) {
- if (DEBUG) {
- Log.v(TAG, "connectToRemoteAndConfigure - iorapd is disabled, skip rest of work");
- }
- // When we see that iorapd is disabled (when system server comes up),
- // it stays disabled permanently until the next system server reset.
-
- // TODO: consider listening to property changes as a callback, then we can
- // be more dynamic about handling enable/disable.
- return true;
- }
-
- // Connect to the native binder service.
- mIorapRemote = provideIorapRemote();
- if (mIorapRemote == null) {
- if (DEBUG) {
- Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?");
- }
- return false;
- }
- invokeRemote(mIorapRemote,
- (IIorap remote) -> remote.setTaskListener(new RemoteTaskListener()) );
- registerInProcessListenersLocked();
-
- Log.i(TAG, "Connected to iorapd native service.");
-
- return true;
- }
-
- private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
- private final EventSequenceValidator mEventSequenceValidator = new EventSequenceValidator();
- private final DexOptPackagesUpdated mDexOptPackagesUpdated = new DexOptPackagesUpdated();
- private boolean mRegisteredListeners = false;
-
- private void registerInProcessListenersLocked() {
- if (mRegisteredListeners) {
- // Listeners are registered only once (idempotent operation).
- //
- // Today listeners are tolerant of the remote side going away
- // by handling remote errors.
- //
- // We could try to 'unregister' the listener when we get a binder disconnect,
- // but we'd still have to handle the case of encountering synchronous errors so
- // it really wouldn't be a win (other than having less log spew).
- return;
- }
-
- // Listen to App Launch Sequence events from ActivityTaskManager,
- // and forward them to the native binder service.
- ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
- provideLaunchObserverRegistry();
- launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver);
- launchObserverRegistry.registerLaunchObserver(mEventSequenceValidator);
-
- BackgroundDexOptService.getService().addPackagesUpdatedListener(
- mDexOptPackagesUpdated);
-
-
- mRegisteredListeners = true;
- }
-
- private class DexOptPackagesUpdated implements BackgroundDexOptService.PackagesUpdatedListener {
- @Override
- public void onPackagesUpdated(ArraySet<String> updatedPackages) {
- String[] updated = updatedPackages.toArray(new String[0]);
- for (String packageName : updated) {
- Log.d(TAG, "onPackagesUpdated: " + packageName);
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onDexOptEvent(RequestId.nextValueForSequence(),
- DexOptEvent.createPackageUpdate(packageName))
- );
- }
- }
- }
-
- private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
- // We add a synthetic sequence ID here to make it easier to differentiate new
- // launch sequences on the native side.
- private @AppLaunchEvent.SequenceId long mSequenceId = -1;
-
- // All callbacks occur on the same background thread. Don't synchronize explicitly.
-
- @Override
- public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
- // #onIntentStarted [is the only transition that] initiates a new launch sequence.
- ++mSequenceId;
-
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s, %d)",
- mSequenceId, intent, timestampNs));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.IntentStarted(mSequenceId, intent, timestampNs))
- );
- }
-
- @Override
- public void onIntentFailed() {
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.IntentFailed(mSequenceId))
- );
- }
-
- @Override
- public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
- @Temperature int temperature) {
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)",
- mSequenceId, activity, temperature));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature))
- );
- }
-
- @Override
- public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)",
- mSequenceId, activity));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId,
- activity)));
- }
-
- @Override
- public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
- long timestampNs) {
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s, %d)",
- mSequenceId, activity, timestampNs));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.ActivityLaunchFinished(mSequenceId,
- activity,
- timestampNs))
- );
- }
-
- @Override
- public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
- long timestampNs) {
- if (DEBUG) {
- Log.v(TAG, String.format("AppLaunchObserver#onReportFullyDrawn(%d, %s, %d)",
- mSequenceId, activity, timestampNs));
- }
-
- invokeRemote(mIorapRemote,
- (IIorap remote) ->
- remote.onAppLaunchEvent(RequestId.nextValueForSequence(),
- new AppLaunchEvent.ReportFullyDrawn(mSequenceId, activity, timestampNs))
- );
- }
- }
-
- /**
- * Debugging:
- *
- * $> adb shell dumpsys jobscheduler
- *
- * Search for 'IorapdJobServiceProxy'.
- *
- * JOB #1000/283673059: 6e54ed android/com.google.android.startop.iorap.IorapForwardingService$IorapdJobServiceProxy
- * ^ ^ ^
- * (uid, job id) ComponentName(package/class)
- *
- * Forcing the job to be run, ignoring constraints:
- *
- * $> adb shell cmd jobscheduler run -f android 283673059
- * ^ ^
- * package job_id
- *
- * ------------------------------------------------------------
- *
- * This class is instantiated newly by the JobService every time
- * it wants to run a new job.
- *
- * We need to forward invocations to the current running instance of
- * IorapForwardingService#IorapdJobService.
- *
- * Visibility: Must be accessible from android.app.AppComponentFactory
- */
- public static class IorapdJobServiceProxy extends JobService {
-
- public IorapdJobServiceProxy() {
- getActualIorapdJobService().bindProxy(this);
- }
-
-
- @NonNull
- private IorapdJobService getActualIorapdJobService() {
- // Can't ever be null, because the guarantee is that the
- // IorapForwardingService is always running.
- // We are in the same process as Job Service.
- return sSelfService.mJobService;
- }
-
- // Called by system to start the job.
- @Override
- public boolean onStartJob(JobParameters params) {
- return getActualIorapdJobService().onStartJob(params);
- }
-
- // Called by system to prematurely stop the job.
- @Override
- public boolean onStopJob(JobParameters params) {
- return getActualIorapdJobService().onStopJob(params);
- }
- }
-
- private class IorapdJobService extends JobService {
- private final ComponentName IORAPD_COMPONENT_NAME;
-
- private final Object mLock = new Object();
- // Jobs currently running remotely on iorapd.
- // They were started by the JobScheduler and need to be finished.
- private final HashMap<RequestId, JobParameters> mRunningJobs = new HashMap<>();
-
- private final JobInfo IORAPD_JOB_INFO;
-
- private volatile IorapdJobServiceProxy mProxy;
-
- public void bindProxy(IorapdJobServiceProxy proxy) {
- mProxy = proxy;
- }
-
- // Create a new job service which immediately schedules a 24-hour idle maintenance mode
- // background job to execute.
- public IorapdJobService(Context context) {
- if (DEBUG) {
- Log.v(TAG, "IorapdJobService (Context=" + context.toString() + ")");
- }
-
- // Schedule the proxy class to be instantiated by the JobScheduler
- // when it is time to invoke background jobs for IorapForwardingService.
-
-
- // This also needs a BIND_JOB_SERVICE permission in
- // frameworks/base/core/res/AndroidManifest.xml
- IORAPD_COMPONENT_NAME = new ComponentName(context, IorapdJobServiceProxy.class);
-
- JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_IORAPD, IORAPD_COMPONENT_NAME);
- builder.setPeriodic(JOB_INTERVAL_MS);
-
- builder.setRequiresCharging(true);
- builder.setRequiresDeviceIdle(true);
-
- builder.setRequiresStorageNotLow(true);
-
- IORAPD_JOB_INFO = builder.build();
-
- JobScheduler js = context.getSystemService(JobScheduler.class);
- js.schedule(IORAPD_JOB_INFO);
- Log.d(TAG,
- "BgJob Scheduled (jobId=" + JOB_ID_IORAPD
- + ", interval: " + JOB_INTERVAL_MS + "ms)");
- }
-
- // Called by system to start the job.
- @Override
- public boolean onStartJob(JobParameters params) {
- // Tell iorapd to start a background job.
- Log.d(TAG, "Starting background job: " + params.toString());
-
- mAbortIdleCompilation.set(false);
- // PackageManagerService starts before IORap service.
- PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
- List<String> pkgs = pm.getAllPackages();
- runIdleCompilationAsync(params, pkgs);
- return true;
- }
-
- private void runIdleCompilationAsync(final JobParameters params, final List<String> pkgs) {
- new Thread("IORap_IdleCompilation") {
- @Override
- public void run() {
- for (int i = 0; i < pkgs.size(); i++) {
- String pkg = pkgs.get(i);
- if (mAbortIdleCompilation.get()) {
- Log.i(TAG, "The idle compilation is aborted");
- return;
- }
-
- // We wait until that job's sequence ID returns to us with 'Completed',
- RequestId request;
- synchronized (mLock) {
- // TODO: would be cleaner if we got the request from the
- // 'invokeRemote' function. Better yet, consider
- // a Pair<RequestId, Future<TaskResult>> or similar.
- request = RequestId.nextValueForSequence();
- mRunningJobs.put(request, params);
- }
-
- Log.i(TAG, String.format("IORap compile package: %s, [%d/%d]",
- pkg, i + 1, pkgs.size()));
- boolean shouldUpdateVersions = (i == 0);
- if (!invokeRemote(mIorapRemote, (IIorap remote) ->
- remote.onJobScheduledEvent(request,
- JobScheduledEvent.createIdleMaintenance(
- JobScheduledEvent.TYPE_START_JOB,
- params,
- pkg,
- shouldUpdateVersions)))) {
- synchronized (mLock) {
- mRunningJobs.remove(request); // Avoid memory leaks.
- }
- }
-
- // Wait until the job is complete and removed from the running jobs.
- retryWithTimeout(TIMEOUT, () -> {
- synchronized (mLock) {
- return !mRunningJobs.containsKey(request);
- }
- });
- }
-
- // Finish the job after all packages are compiled.
- if (mProxy != null) {
- mProxy.jobFinished(params, /*reschedule*/false);
- }
- }
- }.start();
- }
-
- /** Retry until timeout. */
- private boolean retryWithTimeout(final Duration timeout, BooleanSupplier supplier) {
- long totalSleepTimeMs = 0L;
- long sleepIntervalMs = 10L;
- while (true) {
- if (supplier.getAsBoolean()) {
- return true;
- }
- try {
- TimeUnit.MILLISECONDS.sleep(sleepIntervalMs);
- } catch (InterruptedException e) {
- Log.e(TAG, e.getMessage());
- return false;
- }
-
- totalSleepTimeMs += sleepIntervalMs;
- if (totalSleepTimeMs > timeout.toMillis()) {
- return false;
- }
- }
- }
-
- // Called by system to prematurely stop the job.
- @Override
- public boolean onStopJob(JobParameters params) {
- // As this is unexpected behavior, print a warning.
- Log.w(TAG, "onStopJob(params=" + params.toString() + ")");
- mAbortIdleCompilation.set(true);
-
- // Yes, retry the job at a later time no matter what.
- return true;
- }
-
- // Listen to *all* task completes for all requests.
- // The majority of these might be unrelated to background jobs.
- public void onIorapdTaskCompleted(RequestId requestId) {
- JobParameters jobParameters;
- synchronized (mLock) {
- jobParameters = mRunningJobs.remove(requestId);
- }
-
- // Typical case: This was a task callback unrelated to our jobs.
- if (jobParameters == null) {
- return;
- }
-
- if (DEBUG) {
- Log.v(TAG,
- String.format("IorapdJobService#onIorapdTaskCompleted(%s), found params=%s",
- requestId, jobParameters));
- }
-
- Log.d(TAG, "Finished background job: " + jobParameters.toString());
- }
-
- public void onIorapdDisconnected() {
- synchronized (mLock) {
- mRunningJobs.clear();
- }
-
- if (DEBUG) {
- Log.v(TAG, String.format("IorapdJobService#onIorapdDisconnected"));
- }
-
- // TODO: should we try to resubmit all incomplete jobs after it's reconnected?
- }
- }
-
- private class RemoteTaskListener extends ITaskListener.Stub {
- @Override
- public void onProgress(RequestId requestId, TaskResult result) throws RemoteException {
- if (DEBUG) {
- Log.v(TAG,
- String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result));
- }
-
- // TODO: implement rest.
- }
-
- @Override
- public void onComplete(RequestId requestId, TaskResult result) throws RemoteException {
- if (DEBUG) {
- Log.v(TAG,
- String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result));
- }
-
- if (mJobService != null) {
- mJobService.onIorapdTaskCompleted(requestId);
- }
-
- // TODO: implement rest.
- }
- }
-
- /** Allow passing lambdas to #invokeRemote */
- private interface RemoteRunnable {
- // TODO: run(RequestId) ?
- void run(IIorap iorap) throws RemoteException;
- }
-
- // Always pass in the iorap directly here to avoid data race.
- private static boolean invokeRemote(IIorap iorap, RemoteRunnable r) {
- if (iorap == null) {
- Log.w(TAG, "IIorap went to null in this thread, drop invokeRemote.");
- return false;
- }
- try {
- r.run(iorap);
- return true;
- } catch (RemoteException e) {
- // This could be a logic error (remote side returning error), which we need to fix.
- //
- // This could also be a DeadObjectException in which case its probably just iorapd
- // being manually restarted.
- //
- // Don't make any assumption, since DeadObjectException could also mean iorapd crashed
- // unexpectedly.
- //
- // DeadObjectExceptions are recovered from using DeathRecipient and #linkToDeath.
- handleRemoteError(e);
- return false;
- }
- }
-
- private static void handleRemoteError(Throwable t) {
- if (WTF_CRASH) {
- // In development modes, we just want to crash.
- throw new AssertionError("unexpected remote error", t);
- } else {
- // Log to wtf which gets sent to dropbox, and in system_server this does not crash.
- Log.wtf(TAG, t);
- }
- }
-
- // Encode A-Z bitstring into bits. Every character is bits.
- // Characters outside of the range [a,z] are considered out of range.
- //
- // The least significant bits hold the last character.
- // First 2 bits are left as 0.
- private static int encodeEnglishAlphabetStringIntoInt(String name) {
- int value = 0;
-
- final int CHARS_PER_INT = 6;
- final int BITS_PER_CHAR = 5;
- // Note: 2 top bits are unused, this also means our values are non-negative.
- final char CHAR_LOWER = 'a';
- final char CHAR_UPPER = 'z';
-
- if (name.length() > CHARS_PER_INT) {
- throw new IllegalArgumentException(
- "String too long. Cannot encode more than 6 chars: " + name);
- }
-
- for (int i = 0; i < name.length(); ++i) {
- char c = name.charAt(i);
-
- if (c < CHAR_LOWER || c > CHAR_UPPER) {
- throw new IllegalArgumentException("String has out-of-range [a-z] chars: " + name);
- }
-
- // Avoid sign extension during promotion.
- int cur_value = (c & 0xFFFF) - (CHAR_LOWER & 0xFFFF);
- if (cur_value >= (1 << BITS_PER_CHAR)) {
- throw new AssertionError("wtf? i=" + i + ", name=" + name);
- }
-
- value = value << BITS_PER_CHAR;
- value = value | cur_value;
- }
-
- return value;
- }
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
deleted file mode 100644
index b91dd71..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.app.job.JobParameters;
-import android.annotation.NonNull;
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Forward JobService events to iorapd. <br /><br />
- *
- * iorapd sometimes need to use background jobs. Forwarding these events to iorapd
- * notifies iorapd when it is an opportune time to execute these background jobs.
- *
- * @hide
- */
-public class JobScheduledEvent implements Parcelable {
-
- /** JobService#onJobStarted */
- public static final int TYPE_START_JOB = 0;
- /** JobService#onJobStopped */
- public static final int TYPE_STOP_JOB = 1;
- private static final int TYPE_MAX = 1;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_START_JOB,
- TYPE_STOP_JOB,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
-
- /** @see JobParameters#getJobId() */
- public final int jobId;
-
- public final String packageName;
-
- public final boolean shouldUpdateVersions;
-
- /** Device is 'idle' and it's charging (plugged in). */
- public static final int SORT_IDLE_MAINTENANCE = 0;
- private static final int SORT_MAX = 0;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "SORT_" }, value = {
- SORT_IDLE_MAINTENANCE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Sort {}
-
- /**
- * Roughly corresponds to the {@code extras} fields in a JobParameters.
- */
- @Sort public final int sort;
-
- /**
- * Creates a {@link #SORT_IDLE_MAINTENANCE} event from the type and job parameters.
- *
- * Only the job ID is retained from {@code jobParams}, all other param info is dropped.
- */
- @NonNull
- public static JobScheduledEvent createIdleMaintenance(
- @Type int type, JobParameters jobParams, String packageName, boolean shouldUpdateVersions) {
- return new JobScheduledEvent(
- type, jobParams.getJobId(), SORT_IDLE_MAINTENANCE, packageName, shouldUpdateVersions);
- }
-
- private JobScheduledEvent(@Type int type,
- int jobId,
- @Sort int sort,
- String packageName,
- boolean shouldUpdateVersions) {
- this.type = type;
- this.jobId = jobId;
- this.sort = sort;
- this.packageName = packageName;
- this.shouldUpdateVersions = shouldUpdateVersions;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- // No check for 'jobId': any int is valid.
- CheckHelpers.checkTypeInRange(sort, SORT_MAX);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof JobScheduledEvent) {
- return equals((JobScheduledEvent) other);
- }
- return false;
- }
-
- private boolean equals(JobScheduledEvent other) {
- return type == other.type &&
- jobId == other.jobId &&
- sort == other.sort &&
- packageName.equals(other.packageName) &&
- shouldUpdateVersions == other.shouldUpdateVersions;
- }
-
- @Override
- public String toString() {
- return String.format(
- "{type: %d, jobId: %d, sort: %d, packageName: %s, shouldUpdateVersions %b}",
- type, jobId, sort, packageName, shouldUpdateVersions);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- out.writeInt(jobId);
- out.writeInt(sort);
- out.writeString(packageName);
- out.writeBoolean(shouldUpdateVersions);
-
- // We do not parcel the entire JobParameters here because there is no C++ equivalent
- // of that class [which the iorapd side of the binder interface requires].
- }
-
- private JobScheduledEvent(Parcel in) {
- this.type = in.readInt();
- this.jobId = in.readInt();
- this.sort = in.readInt();
- this.packageName = in.readString();
- this.shouldUpdateVersions = in.readBoolean();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<JobScheduledEvent> CREATOR
- = new Parcelable.Creator<JobScheduledEvent>() {
- public JobScheduledEvent createFromParcel(Parcel in) {
- return new JobScheduledEvent(in);
- }
-
- public JobScheduledEvent[] newArray(int size) {
- return new JobScheduledEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java b/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java
deleted file mode 100644
index aa4eea7..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/PackageEvent.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.annotation.NonNull;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.net.Uri;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Forward package manager events to iorapd. <br /><br />
- *
- * Knowing when packages are modified by the system are a useful tidbit to help with performance:
- * for example when a package is replaced, it could be a hint used to invalidate any collected
- * io profiles used for prefetching or pinning.
- *
- * @hide
- */
-public class PackageEvent implements Parcelable {
-
- /** @see android.content.Intent#ACTION_PACKAGE_REPLACED */
- public static final int TYPE_REPLACED = 0;
- private static final int TYPE_MAX = 0;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_REPLACED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
-
- /** The path that a package is installed in, for example {@code /data/app/.../base.apk}. */
- public final Uri packageUri;
- /** The name of the package, for example {@code com.android.calculator}. */
- public final String packageName;
-
- @NonNull
- public static PackageEvent createReplaced(Uri packageUri, String packageName) {
- return new PackageEvent(TYPE_REPLACED, packageUri, packageName);
- }
-
- private PackageEvent(@Type int type, Uri packageUri, String packageName) {
- this.type = type;
- this.packageUri = packageUri;
- this.packageName = packageName;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- Objects.requireNonNull(packageUri, "packageUri");
- Objects.requireNonNull(packageName, "packageName");
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof PackageEvent) {
- return equals((PackageEvent) other);
- }
- return false;
- }
-
- private boolean equals(PackageEvent other) {
- return type == other.type &&
- Objects.equals(packageUri, other.packageUri) &&
- Objects.equals(packageName, other.packageName);
- }
-
- @Override
- public String toString() {
- return String.format("{packageUri: %s, packageName: %s}", packageUri, packageName);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- packageUri.writeToParcel(out, flags);
- out.writeString(packageName);
- }
-
- private PackageEvent(Parcel in) {
- this.type = in.readInt();
- this.packageUri = Uri.CREATOR.createFromParcel(in);
- this.packageName = in.readString();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<PackageEvent> CREATOR
- = new Parcelable.Creator<PackageEvent>() {
- public PackageEvent createFromParcel(Parcel in) {
- return new PackageEvent(in);
- }
-
- public PackageEvent[] newArray(int size) {
- return new PackageEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java b/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
deleted file mode 100644
index 503e1c6..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/RequestId.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.NonNull;
-
-/**
- * Uniquely identify an {@link com.google.android.startop.iorap.IIorap} method invocation,
- * used for asynchronous callbacks by the server. <br /><br />
- *
- * As all system server binder calls must be {@code oneway}, this means all invocations
- * into {@link com.google.android.startop.iorap.IIorap} are non-blocking. The request ID
- * exists to associate all calls with their respective callbacks in
- * {@link com.google.android.startop.iorap.ITaskListener}.
- *
- * @see com.google.android.startop.iorap.IIorap
- *
- * @hide
- */
-public class RequestId implements Parcelable {
-
- public final long requestId;
-
- private static Object mLock = new Object();
- private static long mNextRequestId = 0;
-
- /**
- * Create a monotonically increasing request ID.<br /><br />
- *
- * It is invalid to re-use the same request ID for multiple method calls on
- * {@link com.google.android.startop.iorap.IIorap}; a new request ID must be created
- * each time.
- */
- @NonNull public static RequestId nextValueForSequence() {
- long currentRequestId;
- synchronized (mLock) {
- currentRequestId = mNextRequestId;
- ++mNextRequestId;
- }
- return new RequestId(currentRequestId);
- }
-
- private RequestId(long requestId) {
- this.requestId = requestId;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- if (requestId < 0) {
- throw new IllegalArgumentException("request id must be non-negative");
- }
- }
-
- @Override
- public String toString() {
- return String.format("{requestId: %d}", requestId);
- }
-
- @Override
- public int hashCode() {
- return Long.hashCode(requestId);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof RequestId) {
- return equals((RequestId) other);
- }
- return false;
- }
-
- private boolean equals(RequestId other) {
- return requestId == other.requestId;
- }
-
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(requestId);
- }
-
- private RequestId(Parcel in) {
- requestId = in.readLong();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<RequestId> CREATOR
- = new Parcelable.Creator<RequestId>() {
- public RequestId createFromParcel(Parcel in) {
- return new RequestId(in);
- }
-
- public RequestId[] newArray(int size) {
- return new RequestId[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java
deleted file mode 100644
index 75d47f9..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceEvent.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Forward system service events to iorapd.
- *
- * @see com.android.server.SystemService
- *
- * @hide
- */
-public class SystemServiceEvent implements Parcelable {
-
- /** @see com.android.server.SystemService#onBootPhase */
- public static final int TYPE_BOOT_PHASE = 0;
- /** @see com.android.server.SystemService#onStart */
- public static final int TYPE_START = 1;
- private static final int TYPE_MAX = TYPE_START;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_BOOT_PHASE,
- TYPE_START,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
-
- // TODO: do we want to pass the exact build phase enum?
-
- public SystemServiceEvent(@Type int type) {
- this.type = type;
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- }
-
- @Override
- public String toString() {
- return String.format("{type: %d}", type);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof SystemServiceEvent) {
- return equals((SystemServiceEvent) other);
- }
- return false;
- }
-
- private boolean equals(SystemServiceEvent other) {
- return type == other.type;
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- }
-
- private SystemServiceEvent(Parcel in) {
- this.type = in.readInt();
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<SystemServiceEvent> CREATOR
- = new Parcelable.Creator<SystemServiceEvent>() {
- public SystemServiceEvent createFromParcel(Parcel in) {
- return new SystemServiceEvent(in);
- }
-
- public SystemServiceEvent[] newArray(int size) {
- return new SystemServiceEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java b/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java
deleted file mode 100644
index 2e7bafe..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/SystemServiceUserEvent.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Forward user events to iorapd.<br /><br />
- *
- * Knowledge of the logged-in user is reserved to be used to set-up appropriate policies
- * by iorapd (e.g. to handle user default pinned applications changing).
- *
- * @see com.android.server.SystemService
- *
- * @hide
- */
-public class SystemServiceUserEvent implements Parcelable {
-
- /** @see com.android.server.SystemService#onUserStarting */
- public static final int TYPE_START_USER = 0;
- /** @see com.android.server.SystemService#onUserUnlocking */
- public static final int TYPE_UNLOCK_USER = 1;
- /** @see com.android.server.SystemService#onUserSwitching*/
- public static final int TYPE_SWITCH_USER = 2;
- /** @see com.android.server.SystemService#onUserStopping */
- public static final int TYPE_STOP_USER = 3;
- /** @see com.android.server.SystemService#onUserStopped */
- public static final int TYPE_CLEANUP_USER = 4;
- private static final int TYPE_MAX = TYPE_CLEANUP_USER;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "TYPE_" }, value = {
- TYPE_START_USER,
- TYPE_UNLOCK_USER,
- TYPE_SWITCH_USER,
- TYPE_STOP_USER,
- TYPE_CLEANUP_USER,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- @Type public final int type;
- public final int userHandle;
-
- public SystemServiceUserEvent(@Type int type, int userHandle) {
- this.type = type;
- this.userHandle = userHandle;
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkTypeInRange(type, TYPE_MAX);
- if (userHandle < 0) {
- throw new IllegalArgumentException("userHandle must be non-negative");
- }
- }
-
- @Override
- public String toString() {
- return String.format("{type: %d, userHandle: %d}", type, userHandle);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof SystemServiceUserEvent) {
- return equals((SystemServiceUserEvent) other);
- }
- return false;
- }
-
- private boolean equals(SystemServiceUserEvent other) {
- return type == other.type &&
- userHandle == other.userHandle;
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(type);
- out.writeInt(userHandle);
- }
-
- private SystemServiceUserEvent(Parcel in) {
- this.type = in.readInt();
- this.userHandle = in.readInt();
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<SystemServiceUserEvent> CREATOR
- = new Parcelable.Creator<SystemServiceUserEvent>() {
- public SystemServiceUserEvent createFromParcel(Parcel in) {
- return new SystemServiceUserEvent(in);
- }
-
- public SystemServiceUserEvent[] newArray(int size) {
- return new SystemServiceUserEvent[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java b/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java
deleted file mode 100644
index b5fd6d8..0000000
--- a/startop/iorap/src/com/google/android/startop/iorap/TaskResult.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Result data accompanying a request for {@link com.google.android.startop.iorap.ITaskListener}
- * callbacks.<br /><br />
- *
- * Following {@link com.google.android.startop.iorap.IIorap} method invocation,
- * iorapd will issue in-order callbacks for that corresponding {@link RequestId}.<br /><br />
- *
- * State transitions are as follows: <br /><br />
- *
- * <pre>
- * ┌─────────────────────────────┐
- * │ ▼
- * ┌───────┐ ┌─────────┐ ╔═══════════╗
- * ──▶ │ BEGAN │ ──▶ │ ONGOING │ ──▶ ║ COMPLETED ║
- * └───────┘ └─────────┘ ╚═══════════╝
- * │ │
- * │ │
- * ▼ │
- * ╔═══════╗ │
- * ──▶ ║ ERROR ║ ◀─────┘
- * ╚═══════╝
- *
- * </pre> <!-- system/iorap/docs/binder/TaskResult.dot -->
- *
- * @hide
- */
-public class TaskResult implements Parcelable {
-
- public static final int STATE_BEGAN = 0;
- public static final int STATE_ONGOING = 1;
- public static final int STATE_COMPLETED = 2;
- public static final int STATE_ERROR = 3;
- private static final int STATE_MAX = STATE_ERROR;
-
- /** @hide */
- @IntDef(flag = true, prefix = { "STATE_" }, value = {
- STATE_BEGAN,
- STATE_ONGOING,
- STATE_COMPLETED,
- STATE_ERROR,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface State {}
-
- @State public final int state;
-
- @Override
- public String toString() {
- return String.format("{state: %d}", state);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else if (other instanceof TaskResult) {
- return equals((TaskResult) other);
- }
- return false;
- }
-
- private boolean equals(TaskResult other) {
- return state == other.state;
- }
-
- public TaskResult(@State int state) {
- this.state = state;
-
- checkConstructorArguments();
- }
-
- private void checkConstructorArguments() {
- CheckHelpers.checkStateInRange(state, STATE_MAX);
- }
-
- //<editor-fold desc="Binder boilerplate">
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(state);
- }
-
- private TaskResult(Parcel in) {
- state = in.readInt();
-
- checkConstructorArguments();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<TaskResult> CREATOR
- = new Parcelable.Creator<TaskResult>() {
- public TaskResult createFromParcel(Parcel in) {
- return new TaskResult(in);
- }
-
- public TaskResult[] newArray(int size) {
- return new TaskResult[size];
- }
- };
- //</editor-fold>
-}
diff --git a/startop/iorap/stress/Android.bp b/startop/iorap/stress/Android.bp
deleted file mode 100644
index 6e8725d..0000000
--- a/startop/iorap/stress/Android.bp
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// 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.
-//
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-cc_binary {
- name: "iorap.stress.memory",
- srcs: ["main_memory.cc"],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-unused-parameter"
- ],
-
- shared_libs: [
- "libbase"
- ],
-
- host_supported: true,
-}
diff --git a/startop/iorap/stress/main_memory.cc b/startop/iorap/stress/main_memory.cc
deleted file mode 100644
index 1f26861..0000000
--- a/startop/iorap/stress/main_memory.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-//
-// 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.
-//
-
-#include <chrono>
-#include <fstream>
-#include <iostream>
-#include <random>
-#include <string>
-
-#include <string.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-
-#include <android-base/parseint.h>
-
-static constexpr size_t kBytesPerMb = 1048576;
-const size_t kMemoryAllocationSize = 2 * 1024 * kBytesPerMb;
-
-#define USE_MLOCKALL 0
-
-std::string GetProcessStatus(const char* key) {
- // Build search pattern of key and separator.
- std::string pattern(key);
- pattern.push_back(':');
-
- // Search for status lines starting with pattern.
- std::ifstream fs("/proc/self/status");
- std::string line;
- while (std::getline(fs, line)) {
- if (strncmp(pattern.c_str(), line.c_str(), pattern.size()) == 0) {
- // Skip whitespace in matching line (if any).
- size_t pos = line.find_first_not_of(" \t", pattern.size());
- if (pos == std::string::npos) {
- break;
- }
- return std::string(line, pos);
- }
- }
- return "<unknown>";
-}
-
-int main(int argc, char** argv) {
- size_t allocationSize = 0;
- if (argc >= 2) {
- if (!android::base::ParseUint(argv[1], /*out*/&allocationSize)) {
- std::cerr << "Failed to parse the allocation size (must be 0,MAX_SIZE_T)" << std::endl;
- return 1;
- }
- } else {
- allocationSize = kMemoryAllocationSize;
- }
-
- void* mem = malloc(allocationSize);
- if (mem == nullptr) {
- std::cerr << "Malloc failed" << std::endl;
- return 1;
- }
-
- volatile int* imem = static_cast<int *>(mem); // don't optimize out memory usage
-
- size_t imemCount = allocationSize / sizeof(int);
-
- std::cout << "Allocated " << allocationSize << " bytes" << std::endl;
-
- auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
- std::mt19937 mt_rand(seed);
-
- size_t randPrintCount = 10;
-
- // Write random numbers:
- // * Ensures each page is resident
- // * Avoids zeroed out pages (zRAM)
- // * Avoids same-page merging
- for (size_t i = 0; i < imemCount; ++i) {
- imem[i] = mt_rand();
-
- if (i < randPrintCount) {
- std::cout << "Generated random value: " << imem[i] << std::endl;
- }
- }
-
-#if USE_MLOCKALL
- /*
- * Lock all pages from the address space of this process.
- */
- if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
- std::cerr << "Mlockall failed" << std::endl;
- return 1;
- }
-#else
- // Use mlock because of the predictable VmLck size.
- // Using mlockall tends to bring in anywhere from 2-2.5GB depending on the device.
- if (mlock(mem, allocationSize) != 0) {
- std::cerr << "Mlock failed" << std::endl;
- return 1;
- }
-#endif
-
- // Validate memory is actually resident and locked with:
- // $> cat /proc/$(pidof iorap.stress.memory)/status | grep VmLck
- std::cout << "Locked memory (VmLck) = " << GetProcessStatus("VmLck") << std::endl;
-
- std::cout << "Press any key to terminate" << std::endl;
- int any_input;
- std::cin >> any_input;
-
- std::cout << "Terminating..." << std::endl;
-
- munlockall();
- free(mem);
-
- return 0;
-}
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
deleted file mode 100644
index ad3d001..0000000
--- a/startop/iorap/tests/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (C) 2018 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.
-
-// TODO: once b/80095087 is fixed, rewrite this back to android_test
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library {
- name: "libiorap-java-test-lib",
- srcs: ["src/**/*.kt"],
- static_libs: [
- // Non-test dependencies
- // library under test
- "services.startop.iorap",
- // need the system_server code to be on the classpath,
- "services.core",
- // Test Dependencies
- // test android dependencies
- "platform-test-annotations",
- "androidx.test.rules",
- // test framework dependencies
- "mockito-target-inline-minus-junit4",
- // "mockito-target-minus-junit4",
- // Mockito also requires JNI (see Android.mk)
- // and android:debuggable=true (see AndroidManifest.xml)
- "truth-prebuilt",
- ],
- // sdk_version: "current",
- // certificate: "platform",
- libs: [
- "android.test.base",
- "android.test.runner",
- ],
- // test_suites: ["device-tests"],
-}
-
-android_test {
- name: "libiorap-java-tests",
- dxflags: ["--multi-dex"],
- test_suites: ["device-tests"],
- static_libs: ["libiorap-java-test-lib"],
- compile_multilib: "both",
- jni_libs: [
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- "libmultiplejvmtiagentsinterferenceagent",
- ],
- libs: [
- "android.test.base",
- "android.test.runner",
- ],
- // Use private APIs
- certificate: "platform",
- platform_apis: true,
-}
diff --git a/startop/iorap/tests/AndroidManifest.xml b/startop/iorap/tests/AndroidManifest.xml
deleted file mode 100644
index b967e72..0000000
--- a/startop/iorap/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-<!--suppress AndroidUnknownAttribute -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.startop.iorap.tests"
- android:sharedUserId="com.google.android.startop.iorap.tests"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <!--suppress AndroidDomInspection -->
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.google.android.startop.iorap.tests" />
-
- <!--
- 'debuggable=true' is required to properly load mockito jvmti dependencies,
- otherwise it gives the following error at runtime:
-
- Openjdkjvmti plugin was loaded on a non-debuggable Runtime.
- Plugin was loaded too late to change runtime state to DEBUGGABLE. -->
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-</manifest>
diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml
deleted file mode 100644
index 6102c44..0000000
--- a/startop/iorap/tests/AndroidTest.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<configuration description="Runs libiorap-java-tests.">
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="apct-instrumentation" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="libiorap-java-tests.apk" />
- </target_preparer>
-
- <!--
- Our IIorapIntegrationTest.kt requires setlinux to be disabled:
- it connects to the iorapd binder service but this requires selinux permissions:
-
- avc: denied { find } for service=iorapd pid=2738 uid=10050
- scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:iorapd_service:s0
- tclass=service_manager permissive=0
- -->
- <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer">
- </target_preparer>
-
- <!-- do not use DeviceSetup#set-property because it reboots the device b/136200738.
- furthermore the changes in /data/local.prop don't actually seem to get picked up.
- -->
- <target_preparer
- class="com.android.tradefed.targetprep.DeviceSetup">
- <!-- we need this magic flag, otherwise it always reboots and breaks the selinux -->
- <option name="force-skip-system-props" value="true" />
-
- <!-- Crash instead of using Log.wtf within the system_server iorap code. -->
- <option name="run-command" value="setprop iorapd.forwarding_service.wtf_crash true" />
- <!-- IIorapd has fake behavior: it doesn't do anything but reply with 'DONE' status -->
- <option name="run-command" value="setprop iorapd.binder.fake true" />
-
- <!-- iorapd does not pick up the above changes until we restart it -->
- <option name="run-command" value="stop iorapd" />
- <option name="run-command" value="start iorapd" />
- <!-- give it some time to restart the service; otherwise the first unit test might fail -->
- <option name="run-command" value="sleep 1" />
- </target_preparer>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.google.android.startop.iorap.tests" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- </test>
-
- <!-- using DeviceSetup again does not work. we simply leave the device in a semi-bad
- state. there is no way to clean this up as far as I know.
- -->
-
-</configuration>
-
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt
deleted file mode 100644
index 51e407d..0000000
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/AppLaunchEventTest.kt
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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.
- */
-
-package com.google.android.startop.iorap
-
-import android.content.Intent;
-import android.net.Uri
-import android.os.Parcel
-import android.os.Parcelable
-import androidx.test.filters.SmallTest
-import com.google.android.startop.iorap.AppLaunchEvent;
-import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunched
-import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunchCancelled
-import com.google.android.startop.iorap.AppLaunchEvent.ActivityLaunchFinished
-import com.google.android.startop.iorap.AppLaunchEvent.IntentStarted;
-import com.google.android.startop.iorap.AppLaunchEvent.IntentFailed;
-import com.google.android.startop.iorap.AppLaunchEvent.ReportFullyDrawn
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-
-/**
- * Basic unit tests to test all of the [AppLaunchEvent]s in [com.google.android.startop.iorap].
- */
-@SmallTest
-class AppLaunchEventTest {
- /**
- * Test for IntentStarted.
- */
- @Test
- fun testIntentStarted() {
- var intent = Intent()
- val valid = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 1L)
- val copy = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 1L)
- val noneCopy1 = IntentStarted(/* sequenceId= */1L, intent, /* timestampNs= */ 1L)
- val noneCopy2 = IntentStarted(/* sequenceId= */2L, intent, /* timestampNs= */ 2L)
- val noneCopy3 = IntentStarted(/* sequenceId= */2L, Intent(), /* timestampNs= */ 1L)
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy1)
- assertThat(valid).isNotEqualTo(noneCopy2)
- assertThat(valid).isNotEqualTo(noneCopy3)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("IntentStarted{sequenceId=2, intent=Intent { } , timestampNs=1}")
- }
-
- /**
- * Test for IntentFailed.
- */
- @Test
- fun testIntentFailed() {
- val valid = IntentFailed(/* sequenceId= */2L)
- val copy = IntentFailed(/* sequenceId= */2L)
- val noneCopy = IntentFailed(/* sequenceId= */1L)
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("IntentFailed{sequenceId=2}")
- }
-
- /**
- * Test for ActivityLaunched.
- */
- @Test
- fun testActivityLaunched() {
- //var activityRecord =
- val valid = ActivityLaunched(/* sequenceId= */2L, "test".toByteArray(),
- /* temperature= */ 0)
- val copy = ActivityLaunched(/* sequenceId= */2L, "test".toByteArray(),
- /* temperature= */ 0)
- val noneCopy1 = ActivityLaunched(/* sequenceId= */1L, "test".toByteArray(),
- /* temperature= */ 0)
- val noneCopy2 = ActivityLaunched(/* sequenceId= */1L, "test".toByteArray(),
- /* temperature= */ 1)
- val noneCopy3 = ActivityLaunched(/* sequenceId= */1L, "test1".toByteArray(),
- /* temperature= */ 0)
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy1)
- assertThat(valid).isNotEqualTo(noneCopy2)
- assertThat(valid).isNotEqualTo(noneCopy3)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("ActivityLaunched{sequenceId=2, test, temperature=0}")
- }
-
-
- /**
- * Test for ActivityLaunchFinished.
- */
- @Test
- fun testActivityLaunchFinished() {
- val valid = ActivityLaunchFinished(/* sequenceId= */2L, "test".toByteArray(),
- /* timestampNs= */ 1L)
- val copy = ActivityLaunchFinished(/* sequenceId= */2L, "test".toByteArray(),
- /* timestampNs= */ 1L)
- val noneCopy1 = ActivityLaunchFinished(/* sequenceId= */1L, "test".toByteArray(),
- /* timestampNs= */ 1L)
- val noneCopy2 = ActivityLaunchFinished(/* sequenceId= */1L, "test".toByteArray(),
- /* timestampNs= */ 2L)
- val noneCopy3 = ActivityLaunchFinished(/* sequenceId= */2L, "test1".toByteArray(),
- /* timestampNs= */ 1L)
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy1)
- assertThat(valid).isNotEqualTo(noneCopy2)
- assertThat(valid).isNotEqualTo(noneCopy3)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("ActivityLaunchFinished{sequenceId=2, test, timestampNs=1}")
- }
-
- /**
- * Test for ActivityLaunchCancelled.
- */
- @Test
- fun testActivityLaunchCancelled() {
- val valid = ActivityLaunchCancelled(/* sequenceId= */2L, "test".toByteArray())
- val copy = ActivityLaunchCancelled(/* sequenceId= */2L, "test".toByteArray())
- val noneCopy1 = ActivityLaunchCancelled(/* sequenceId= */1L, "test".toByteArray())
- val noneCopy2 = ActivityLaunchCancelled(/* sequenceId= */2L, "test1".toByteArray())
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy1)
- assertThat(valid).isNotEqualTo(noneCopy2)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("ActivityLaunchCancelled{sequenceId=2, test}")
- }
-
- /**
- * Test for ReportFullyDrawn.
- */
- @Test
- fun testReportFullyDrawn() {
- val valid = ReportFullyDrawn(/* sequenceId= */2L, "test".toByteArray(), /* timestampNs= */ 1L)
- val copy = ReportFullyDrawn(/* sequenceId= */2L, "test".toByteArray(), /* timestampNs= */ 1L)
- val noneCopy1 = ReportFullyDrawn(/* sequenceId= */1L, "test".toByteArray(),
- /* timestampNs= */ 1L)
- val noneCopy2 = ReportFullyDrawn(/* sequenceId= */1L, "test".toByteArray(),
- /* timestampNs= */ 1L)
- val noneCopy3 = ReportFullyDrawn(/* sequenceId= */2L, "test1".toByteArray(),
- /* timestampNs= */ 1L)
-
- // equals(Object other)
- assertThat(valid).isEqualTo(copy)
- assertThat(valid).isNotEqualTo(noneCopy1)
- assertThat(valid).isNotEqualTo(noneCopy2)
- assertThat(valid).isNotEqualTo(noneCopy3)
-
- // test toString()
- val result = valid.toString()
- assertThat(result).isEqualTo("ReportFullyDrawn{sequenceId=2, test, timestampNs=1}")
- }
-}
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
deleted file mode 100644
index 18c2491..0000000
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap
-
-import android.net.Uri
-import android.os.ServiceManager
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.MediumTest
-import org.junit.Test
-import org.mockito.Mockito.argThat
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.inOrder
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.timeout
-
-// @Ignore("Test is disabled until iorapd is added to init and there's selinux policies for it")
-@MediumTest
-@FlakyTest(bugId = 149098310) // Failing on cuttlefish with SecurityException.
-class IIorapIntegrationTest {
- /**
- * @throws ServiceManager.ServiceNotFoundException if iorapd service could not be found
- */
- private val iorapService: IIorap by lazy {
- // TODO: connect to 'iorapd.stub' which doesn't actually do any work other than reply.
- IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"))
-
- // Use 'adb shell setenforce 0' otherwise this whole test fails,
- // because the servicemanager is not allowed to hand out the binder token for iorapd.
-
- // TODO: implement the selinux policies for iorapd.
- }
-
- // A dummy binder stub implementation is required to use with mockito#spy.
- // Mockito overrides the methods at runtime and tracks how methods were invoked.
- open class DummyTaskListener : ITaskListener.Stub() {
- // Note: make parameters nullable to avoid the kotlin IllegalStateExceptions
- // from using the mockito matchers (eq, argThat, etc).
- override fun onProgress(requestId: RequestId?, result: TaskResult?) {
- }
-
- override fun onComplete(requestId: RequestId?, result: TaskResult?) {
- }
- }
-
- private fun testAnyMethod(func: (RequestId) -> Unit) {
- val taskListener = spy(DummyTaskListener())!!
-
- // FIXME: b/149098310
- return
-
- try {
- iorapService.setTaskListener(taskListener)
- // Note: Binder guarantees total order for oneway messages sent to the same binder
- // interface, so we don't need any additional blocking here before sending later calls.
-
- // Every new method call should have a unique request id.
- val requestId = RequestId.nextValueForSequence()!!
-
- // Apply the specific function under test.
- func(requestId)
-
- // Typical mockito behavior is to allow any-order callbacks, but we want to test order.
- val inOrder = inOrder(taskListener)
-
- // The "stub" behavior of iorapd is that every request immediately gets a response of
- // BEGAN,ONGOING,COMPLETED
- inOrder.verify(taskListener, timeout(100))
- .onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN })
- inOrder.verify(taskListener, timeout(100))
- .onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING })
- inOrder.verify(taskListener, timeout(100))
- .onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED })
- inOrder.verifyNoMoreInteractions()
- } finally {
- // iorapService.setTaskListener(null)
- // FIXME: null is broken, C++ side sees a non-null object.
- }
- }
-
- @Test
- fun testOnPackageEvent() {
- // FIXME (b/137134253): implement PackageEvent parsing on the C++ side.
- // This is currently (silently: b/137135024) failing because IIorap is 'oneway' and the
- // C++ PackageEvent un-parceling fails since its not implemented fully.
- /*
- testAnyMethod { requestId : RequestId ->
- iorapService.onPackageEvent(requestId,
- PackageEvent.createReplaced(
- Uri.parse("https://www.google.com"), "com.fake.package"))
- }
- */
- }
-
- @Test
- fun testOnAppIntentEvent() {
- testAnyMethod { requestId: RequestId ->
- iorapService.onAppIntentEvent(requestId, AppIntentEvent.createDefaultIntentChanged(
- ActivityInfo("dont care", "dont care"),
- ActivityInfo("dont care 2", "dont care 2")))
- }
- }
-
- @Test
- fun testOnAppLaunchEvent() {
- testAnyMethod { requestId : RequestId ->
- iorapService.onAppLaunchEvent(requestId, AppLaunchEvent.IntentFailed(/*sequenceId*/123))
- }
- }
-
- @Test
- fun testOnSystemServiceEvent() {
- testAnyMethod { requestId: RequestId ->
- iorapService.onSystemServiceEvent(requestId,
- SystemServiceEvent(SystemServiceEvent.TYPE_START))
- }
- }
-
- @Test
- fun testOnSystemServiceUserEvent() {
- testAnyMethod { requestId: RequestId ->
- iorapService.onSystemServiceUserEvent(requestId,
- SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 0))
- }
- }
-}
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
deleted file mode 100644
index 150577a..0000000
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/ParcelablesTest.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2018 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.startop.iorap
-
-import android.net.Uri
-import android.os.Parcel
-import android.os.Parcelable
-import androidx.test.filters.SmallTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import com.google.common.truth.Truth.assertThat
-import org.junit.runners.Parameterized
-
-/**
- * Basic unit tests to ensure that all of the [Parcelable]s in [com.google.android.startop.iorap]
- * have a valid-conforming interface implementation.
- */
-@SmallTest
-@RunWith(Parameterized::class)
-class ParcelablesTest<T : Parcelable>(private val inputData: InputData<T>) {
- companion object {
- private val initialRequestId = RequestId.nextValueForSequence()!!
-
- @JvmStatic
- @Parameterized.Parameters
- fun data() = listOf(
- InputData(
- newActivityInfo(),
- newActivityInfo(),
- ActivityInfo("some package", "some other activity")),
- InputData(
- ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
- ActivityHintEvent(ActivityHintEvent.TYPE_COMPLETED, newActivityInfo()),
- ActivityHintEvent(ActivityHintEvent.TYPE_POST_COMPLETED,
- newActivityInfo())),
- InputData(
- AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
- newActivityInfoOther()),
- AppIntentEvent.createDefaultIntentChanged(newActivityInfo(),
- newActivityInfoOther()),
- AppIntentEvent.createDefaultIntentChanged(newActivityInfoOther(),
- newActivityInfo())),
- InputData(
- PackageEvent.createReplaced(newUri(), "some package"),
- PackageEvent.createReplaced(newUri(), "some package"),
- PackageEvent.createReplaced(newUri(), "some other package")
- ),
- InputData(initialRequestId, cloneRequestId(initialRequestId),
- RequestId.nextValueForSequence()),
- InputData(
- SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
- SystemServiceEvent(SystemServiceEvent.TYPE_BOOT_PHASE),
- SystemServiceEvent(SystemServiceEvent.TYPE_START)),
- InputData(
- SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
- SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER, 12345),
- SystemServiceUserEvent(SystemServiceUserEvent.TYPE_CLEANUP_USER, 12345)),
- InputData(
- TaskResult(TaskResult.STATE_COMPLETED),
- TaskResult(TaskResult.STATE_COMPLETED),
- TaskResult(TaskResult.STATE_ONGOING))
- )
-
- private fun newActivityInfo(): ActivityInfo {
- return ActivityInfo("some package", "some activity")
- }
-
- private fun newActivityInfoOther(): ActivityInfo {
- return ActivityInfo("some package 2", "some activity 2")
- }
-
- private fun newUri(): Uri {
- return Uri.parse("https://www.google.com")
- }
-
- private fun cloneRequestId(requestId: RequestId): RequestId {
- val constructor = requestId::class.java.declaredConstructors[0]
- constructor.isAccessible = true
- return constructor.newInstance(requestId.requestId) as RequestId
- }
- }
-
- /**
- * Test for [Object.equals] implementation.
- */
- @Test
- fun testEquality() {
- assertThat(inputData.valid).isEqualTo(inputData.valid)
- assertThat(inputData.valid).isEqualTo(inputData.validCopy)
- assertThat(inputData.valid).isNotEqualTo(inputData.validOther)
- }
-
- /**
- * Test for [Parcelable] implementation.
- */
- @Test
- fun testParcelRoundTrip() {
- // calling writeToParcel and then T::CREATOR.createFromParcel would return the same data.
- val assertParcels = { it: T, data: InputData<T> ->
- val parcel = Parcel.obtain()
- it.writeToParcel(parcel, 0)
- parcel.setDataPosition(0) // future reads will see all previous writes.
- assertThat(it).isEqualTo(data.createFromParcel(parcel))
- parcel.recycle()
- }
-
- assertParcels(inputData.valid, inputData)
- assertParcels(inputData.validCopy, inputData)
- assertParcels(inputData.validOther, inputData)
- }
-
- data class InputData<T : Parcelable>(val valid: T, val validCopy: T, val validOther: T) {
- val kls = valid.javaClass
- init {
- assertThat(valid).isNotSameInstanceAs(validCopy)
- // Don't use isInstanceOf because of phantom warnings in intellij about Class!
- assertThat(validCopy.javaClass).isEqualTo(valid.javaClass)
- assertThat(validOther.javaClass).isEqualTo(valid.javaClass)
- }
-
- fun createFromParcel(parcel: Parcel): T {
- val field = kls.getDeclaredField("CREATOR")
- val creator = field.get(null) as Parcelable.Creator<T>
-
- return creator.createFromParcel(parcel)
- }
- }
-}