Merge "Add performance tests for Service"
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
index ec5a9c6..23a151c 100644
--- a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -32,5 +32,8 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
+ <service
+ android:name=".TestService"
+ android:exported="true" />
</application>
</manifest>
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
index 1f06121..4e7bb4c 100644
--- a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.os.Looper;
-import android.os.MessageQueue;
import com.android.frameworks.perftests.am.util.Constants;
import com.android.frameworks.perftests.am.util.Utils;
diff --git a/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java
new file mode 100644
index 0000000..b6534fc
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.android.frameworks.perftests.amteststestapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+import com.android.frameworks.perftests.am.util.Constants;
+import com.android.frameworks.perftests.am.util.Utils;
+
+public class TestService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new Binder();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Utils.sendTime(intent, Constants.TYPE_SERVICE_START);
+ return super.onStartCommand(intent, flags, startId);
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
index 661abe9..cf175e0 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -16,8 +16,11 @@
package com.android.frameworks.perftests.am.tests;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
import android.perftests.utils.ManualBenchmarkState;
import android.perftests.utils.PerfManualStatusReporter;
import android.support.test.InstrumentationRegistry;
@@ -26,13 +29,17 @@
import com.android.frameworks.perftests.am.util.TimeReceiver;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.function.LongSupplier;
public class BasePerfTest {
private static final String TAG = BasePerfTest.class.getSimpleName();
+ private static final long AWAIT_SERVICE_CONNECT_MS = 2000;
private TimeReceiver mTimeReceiver;
@@ -52,14 +59,70 @@
TargetPackageUtils.killTargetPackage(mContext);
}
- protected Intent createIntent(String action) {
+ protected void addReceivedTimeNs(String type) {
+ mTimeReceiver.addTimeForTypeToQueue(type, System.nanoTime());
+ }
+
+ protected Intent createServiceIntent() {
+ final Intent intent = new Intent();
+ intent.setClassName(TargetPackageUtils.PACKAGE_NAME,
+ TargetPackageUtils.SERVICE_NAME);
+ putTimeReceiverBinderExtra(intent);
+ return intent;
+ }
+
+ protected ServiceConnection bindAndWaitForConnectedService() {
+ return bindAndWaitForConnectedService(0);
+ }
+
+ protected ServiceConnection bindAndWaitForConnectedService(int flags) {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ final ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ countDownLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+
+ final Intent intent = createServiceIntent();
+ final boolean success = mContext.bindService(intent, serviceConnection,
+ Context.BIND_AUTO_CREATE | flags);
+ Assert.assertTrue("Could not bind to service", success);
+
+ try {
+ boolean connectedSuccess = countDownLatch.await(AWAIT_SERVICE_CONNECT_MS,
+ TimeUnit.MILLISECONDS);
+ Assert.assertTrue("Timeout when waiting for ServiceConnection.onServiceConnected()",
+ connectedSuccess);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ return serviceConnection;
+ }
+
+ protected void unbindFromService(ServiceConnection serviceConnection) {
+ if (serviceConnection != null) {
+ mContext.unbindService(serviceConnection);
+ }
+ }
+
+ protected Intent createBroadcastIntent(String action) {
final Intent intent = new Intent(action);
intent.addFlags(
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- intent.putExtras(mTimeReceiver.createReceiveTimeExtraBinder());
+ putTimeReceiverBinderExtra(intent);
return intent;
}
+ protected void putTimeReceiverBinderExtra(Intent intent) {
+ intent.putExtras(mTimeReceiver.createReceiveTimeExtraBinder());
+ }
+
private void setUpIteration() {
mTimeReceiver.clear();
TargetPackageUtils.killTargetPackage(mContext);
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
index 795f498..f7dab03 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -33,7 +33,8 @@
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+ final Intent intent = createBroadcastIntent(
+ Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -48,7 +49,8 @@
@Test
public void manifestBroadcastNotRunning() {
runPerfFunction(() -> {
- final Intent intent = createIntent(Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
+ final Intent intent = createBroadcastIntent(
+ Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -65,7 +67,8 @@
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createIntent(Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
+ final Intent intent = createBroadcastIntent(
+ Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
final long startTime = System.nanoTime();
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java
new file mode 100644
index 0000000..6d2935a
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.android.frameworks.perftests.am.tests;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ServiceBindPerfTest extends BasePerfTest {
+ /**
+ * Create and return a ServiceConnection that will add the current time with type
+ * Constants.TYPE_SERVICE_CONNECTED.
+ */
+ private ServiceConnection createServiceConnectionReportTime() {
+ return new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ addReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+ }
+
+ /**
+ * Try to bind to the service with the input parameters, throwing a RuntimeException with the
+ * errorMessage on failure.
+ */
+ private void bindService(Intent intent, ServiceConnection serviceConnection, int flags) {
+ final boolean success = mContext.bindService(intent, serviceConnection, flags);
+ Assert.assertTrue("Could not bind to service", success);
+ }
+
+ /**
+ * Benchmark time from Context.bindService() to Service.onBind() when target package is not
+ * running.
+ */
+ @Test
+ public void bindServiceNotRunning() {
+ runPerfFunction(() -> {
+ final Intent intent = createServiceIntent();
+ final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+ final long startTimeNs = System.nanoTime();
+ bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+ try {
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(serviceConnection);
+ }
+ });
+ }
+
+ /**
+ * Benchmark time from Context.bindService() to Service.onBind() when target package is running.
+ */
+ @Test
+ public void bindServiceRunning() {
+ runPerfFunction(() -> {
+ startTargetPackage();
+
+ final Intent intent = createServiceIntent();
+ final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+ final long startTimeNs = System.nanoTime();
+ bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+ try {
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(serviceConnection);
+ }
+ });
+ }
+
+ /**
+ * Benchmark time from Context.bindService() to Service.onBind() when service is already bound
+ * to.
+ */
+ @Test
+ public void bindServiceAlreadyBound() {
+ runPerfFunction(() -> {
+ startTargetPackage();
+
+ final Intent intent = createServiceIntent();
+ final ServiceConnection alreadyBoundServiceConnection = bindAndWaitForConnectedService();
+
+ try {
+ final ServiceConnection serviceConnection = createServiceConnectionReportTime();
+
+ final long startTimeNs = System.nanoTime();
+ try {
+ bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(serviceConnection);
+ }
+ } finally {
+ unbindFromService(alreadyBoundServiceConnection);
+ }
+ });
+ }
+
+ /**
+ * Benchmark time from Context.bindService() (without BIND_ALLOW_OOM_MANAGEMENT) to
+ * Service.onBind() when service is already bound to with BIND_ALLOW_OOM_MANAGEMENT.
+ */
+ @Test
+ public void bindServiceAllowOomManagement() {
+ runPerfFunction(() -> {
+ final Intent intentNoOom = createServiceIntent();
+ final ServiceConnection serviceConnectionOom = bindAndWaitForConnectedService(
+ Context.BIND_ALLOW_OOM_MANAGEMENT);
+
+ try {
+ final ServiceConnection serviceConnectionNoOom =
+ createServiceConnectionReportTime();
+ try {
+ final long startTimeNs = System.nanoTime();
+ bindService(intentNoOom, serviceConnectionNoOom, Context.BIND_AUTO_CREATE);
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_CONNECTED);
+
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(serviceConnectionNoOom);
+ }
+ } finally {
+ unbindFromService(serviceConnectionOom);
+ }
+ });
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
new file mode 100644
index 0000000..626ee02
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.android.frameworks.perftests.am.tests;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.perftests.am.util.Constants;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ServiceStartPerfTest extends BasePerfTest {
+
+ /**
+ * Tries to start the service with the given intent, throwing a RuntimeException with the
+ * errorMessage on failure.
+ */
+ private void startService(Intent intent) {
+ final ComponentName componentName = mContext.startService(intent);
+ Assert.assertNotNull("Could not start service", componentName);
+ }
+
+ /**
+ * Benchmark time from Context.startService() to Service.onStartCommand() when target process is
+ * not running.
+ */
+ @Test
+ public void startServiceNotRunning() {
+ runPerfFunction(() -> {
+ final Intent intent = createServiceIntent();
+
+ final long startTimeNs = System.nanoTime();
+
+ startService(intent);
+
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+ return endTimeNs - startTimeNs;
+ });
+ }
+
+ /**
+ * Benchmark time from Context.startService() to Service.onStartCommand() when target process is
+ * running.
+ */
+ @Test
+ public void startServiceProcessRunning() {
+ runPerfFunction(() -> {
+ startTargetPackage();
+
+ final Intent intent = createServiceIntent();
+
+ final long startTimeNs = System.nanoTime();
+ startService(intent);
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+ return endTimeNs - startTimeNs;
+ });
+ }
+
+ /**
+ * Benchmark time from Context.startService() to Service.onStartCommand() when service is
+ * already bound to.
+ */
+ @Test
+ public void startServiceAlreadyBound() {
+ runPerfFunction(() -> {
+ final ServiceConnection alreadyBoundServiceConnection =
+ bindAndWaitForConnectedService();
+ try {
+ final Intent intent = createServiceIntent();
+
+ final long startTimeNs = System.nanoTime();
+ startService(intent);
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(alreadyBoundServiceConnection);
+ }
+ });
+ }
+
+ /**
+ * Benchmark time from Context.startService() with FLAG_GRANT_READ_URI_PERMISSION to
+ * Service.onStartCommand() when target process is running.
+ */
+ @Test
+ public void startServiceProcessRunningReadUriPermission() {
+ runPerfFunction(() -> {
+ final ServiceConnection alreadyBoundServiceConnection =
+ bindAndWaitForConnectedService();
+ try {
+ final Intent intent = createServiceIntent();
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final long startTimeNs = System.nanoTime();
+ startService(intent);
+ final long endTimeNs = getReceivedTimeNs(Constants.TYPE_SERVICE_START);
+
+ return endTimeNs - startTimeNs;
+ } finally {
+ unbindFromService(alreadyBoundServiceConnection);
+ }
+ });
+ }
+}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
index 26a8e7b..3db8abc 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
@@ -27,6 +27,7 @@
public static final String PACKAGE_NAME = "com.android.frameworks.perftests.amteststestapp";
public static final String ACTIVITY_NAME = PACKAGE_NAME + ".TestActivity";
+ public static final String SERVICE_NAME = PACKAGE_NAME + ".TestService";
private static final long WAIT_TIME_MS = 100L;
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
index 9cf6ee7..a86a5c7 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
@@ -45,20 +45,23 @@
}
}
+ public void addTimeForTypeToQueue(String type, long timeNs) {
+ if (type == null) {
+ throw new IllegalArgumentException("type is null when adding time to queue");
+ }
+ if (timeNs < 0) {
+ throw new RuntimeException(
+ "time is negative/non-existant (" + timeNs + ") when adding time to queue");
+ }
+ mQueue.add(new ReceivedMessage(type, timeNs));
+ }
+
public Bundle createReceiveTimeExtraBinder() {
Bundle extras = new Bundle();
extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, new ITimeReceiverCallback.Stub() {
@Override
public void sendTime(String type, long timeNs) throws RemoteException {
- if (type == null) {
- throw new RuntimeException("receivedType is null");
- }
- if (timeNs < 0) {
- throw new RuntimeException(
- "receivedTime is negative/non-existant: " + timeNs);
- }
- Log.i(TAG, type + " " + timeNs);
- mQueue.add(new ReceivedMessage(type, timeNs));
+ addTimeForTypeToQueue(type, timeNs);
}
});
return extras;
diff --git a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
index f35c2fd..ffb3f84 100644
--- a/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
+++ b/tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java
@@ -19,6 +19,9 @@
public class Constants {
public static final String TYPE_TARGET_PACKAGE_START = "target_package_start";
public static final String TYPE_BROADCAST_RECEIVE = "broadcast_receive";
+ public static final String TYPE_SERVICE_BIND = "service_bind";
+ public static final String TYPE_SERVICE_START = "service_start";
+ public static final String TYPE_SERVICE_CONNECTED = "service_connection_connect";
public static final String ACTION_BROADCAST_MANIFEST_RECEIVE =
"com.android.frameworks.perftests.ACTION_BROADCAST_MANIFEST_RECEIVE";