OSDN Git Service

Add performance tests for Service
authorArthur Eubanks <aeubanks@google.com>
Tue, 9 Jan 2018 19:40:58 +0000 (11:40 -0800)
committerArthur Eubanks <aeubanks@google.com>
Mon, 12 Feb 2018 17:11:35 +0000 (09:11 -0800)
Test: m ActivityManagerPerfTestsTestApp ActivityManagerPerfTests
Test: adb install \
$OUT/data/app/ActivityManagerPerfTestsTestApp/ActivityManagerPerfTestsTestApp.apk
Test: adb install \
$OUT/data/app/ActivityManagerPerfTests/ActivityManagerPerfTests.apk
Test: adb shell am instrument -w -e class \
com.android.frameworks.perftests.am.tests.ServiceStartPerfTest \
com.android.frameworks.perftests.amtests/android.support.test.runner.AndroidJUnitRunner
Test: adb shell am instrument -w -e class \
com.android.frameworks.perftests.am.tests.ServiceBindPerfTest \
com.android.frameworks.perftests.amtests/android.support.test.runner.AndroidJUnitRunner

BUG: 67460485

Change-Id: I16ea5752def13aabd481aeb29f1af0ac04e75f6a

tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestActivity.java
tests/ActivityManagerPerfTests/test-app/src/com/android/frameworks/perftests/amteststestapp/TestService.java [new file with mode: 0644]
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceBindPerfTest.java [new file with mode: 0644]
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java [new file with mode: 0644]
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TargetPackageUtils.java
tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/util/TimeReceiver.java
tests/ActivityManagerPerfTests/utils/src/com/android/frameworks/perftests/am/util/Constants.java

index 021e386..ca91f16 100644 (file)
@@ -29,5 +29,8 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </receiver>
+        <service
+                android:name=".TestService"
+                android:exported="true" />
     </application>
 </manifest>
index 1f06121..4e7bb4c 100644 (file)
@@ -18,7 +18,6 @@ package com.android.frameworks.perftests.amteststestapp;
 
 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 (file)
index 0000000..b6534fc
--- /dev/null
@@ -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);
+    }
+}
index 661abe9..cf175e0 100644 (file)
 
 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.TargetPackageUtils;
 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 @@ public class BasePerfTest {
         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);
index 795f498..f7dab03 100644 (file)
@@ -33,7 +33,8 @@ public class BroadcastPerfTest extends BasePerfTest {
         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 @@ public class BroadcastPerfTest extends BasePerfTest {
     @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 @@ public class BroadcastPerfTest extends BasePerfTest {
         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 (file)
index 0000000..6d2935a
--- /dev/null
@@ -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 (file)
index 0000000..626ee02
--- /dev/null
@@ -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);
+            }
+        });
+    }
+}
index 26a8e7b..3db8abc 100644 (file)
@@ -27,6 +27,7 @@ public class TargetPackageUtils {
 
     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;
 
index 9cf6ee7..a86a5c7 100644 (file)
@@ -45,20 +45,23 @@ public class TimeReceiver {
         }
     }
 
+    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;
index f35c2fd..ffb3f84 100644 (file)
@@ -19,6 +19,9 @@ package com.android.frameworks.perftests.am.util;
 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";