Loading services/tests/servicestests/AndroidTest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <option name="test-file-name" value="JobTestApp.apk" /> <option name="test-file-name" value="ConnTestApp.apk" /> <option name="test-file-name" value="SuspendTestApp.apk" /> <option name="test-file-name" value="SimpleServiceTestApp.apk" /> </target_preparer> <option name="test-tag" value="FrameworksServicesTests" /> Loading services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +132 −0 Original line number Diff line number Diff line Loading @@ -19,20 +19,34 @@ package com.android.server.am; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * Tests for {@link ActivityManager}. Loading @@ -43,12 +57,22 @@ import java.util.List; @FlakyTest(detail = "Promote to presubmit if stable") @Presubmit public class ActivityManagerTest { private static final String TAG = "ActivityManagerTest"; private static final String TEST_APP = "com.android.servicestests.apps.simpleservicetestapp"; private static final String TEST_CLASS = TEST_APP + ".SimpleService"; private static final int TEST_LOOPS = 100; private static final long AWAIT_TIMEOUT = 2000; private static final long CHECK_INTERVAL = 100; private IActivityManager mService; private IRemoteCallback mCallback; private Context mContext; @Before public void setUp() throws Exception { mService = ActivityManager.getService(); mContext = InstrumentationRegistry.getTargetContext(); } @Test Loading @@ -72,4 +96,112 @@ public class ActivityManagerTest { } } } @Test public void testServiceUnbindAndKilling() { for (int i = TEST_LOOPS; i > 0; i--) { runOnce(i); } } private void runOnce(long yieldDuration) { final PackageManager pm = mContext.getPackageManager(); int uid = 0; try { uid = pm.getPackageUid(TEST_APP, 0); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } Intent intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); // Create a service connection with auto creation. CountDownLatch latch = new CountDownLatch(1); final MyServiceConnection autoConnection = new MyServiceConnection(latch); mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } // Create a service connection without any flags. intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); latch = new CountDownLatch(1); MyServiceConnection otherConnection = new MyServiceConnection(latch); mContext.bindService(intent, otherConnection, 0); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } // Inform the remote process to kill itself try { mCallback.sendResult(null); // It's basically a test for race condition, we expect the bringDownServiceLocked() // would find out the hosting process is dead - to do this, technically we should // do killing and unbinding simultaneously; but in reality, the killing would take // a little while, before the signal really kills it; so we do it in the same thread, // and even wait a while after sending killing signal. Thread.sleep(yieldDuration); } catch (RemoteException | InterruptedException e) { fail("Unable to kill the process"); } // Now unbind that auto connection, this should be equivalent to stopService mContext.unbindService(autoConnection); // Now we don't expect the system_server crashes. // Wait for the target process dies long total = 0; for (; total < AWAIT_TIMEOUT; total += CHECK_INTERVAL) { try { if (!targetPackageIsRunning(mContext, uid)) { break; } Thread.sleep(CHECK_INTERVAL); } catch (InterruptedException e) { } } assertTrue("Timeout to wait for the target package dies", total < AWAIT_TIMEOUT); mCallback = null; } private boolean targetPackageIsRunning(Context context, int uid) { final String result = runShellCommand( String.format("cmd activity get-uid-state %d", uid)); return !result.contains("(NONEXISTENT)"); } private static String runShellCommand(String cmd) { try { return UiDevice.getInstance( InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd); } catch (IOException e) { throw new RuntimeException(e); } } private class MyServiceConnection implements ServiceConnection { private CountDownLatch mLatch; MyServiceConnection(CountDownLatch latch) { this.mLatch = latch; } @Override public void onServiceConnected(ComponentName name, IBinder service) { mCallback = IRemoteCallback.Stub.asInterface(service); mLatch.countDown(); } @Override public void onServiceDisconnected(ComponentName name) { } } } services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp 0 → 100644 +30 −0 Original line number Diff line number Diff line // 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. android_test_helper_app { name: "SimpleServiceTestApp", test_suites: ["device-tests"], srcs: ["**/*.java"], platform_apis: true, certificate: "platform", dex_preopt: { enabled: false, }, optimize: { enabled: false, }, } services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.servicestests.apps.simpleservicetestapp"> <application> <service android:name=".SimpleService" android:exported="true" /> </application> </manifest> services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * 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.android.servicestests.apps.simpleservicetestapp; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Process; public class SimpleService extends Service { private final IRemoteCallback.Stub mBinder = new IRemoteCallback.Stub() { @Override public void sendResult(Bundle bundle) { Process.killProcess(Process.myPid()); } }; @Override public IBinder onBind(Intent intent) { return mBinder; } } Loading
services/tests/servicestests/AndroidTest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ <option name="test-file-name" value="JobTestApp.apk" /> <option name="test-file-name" value="ConnTestApp.apk" /> <option name="test-file-name" value="SuspendTestApp.apk" /> <option name="test-file-name" value="SimpleServiceTestApp.apk" /> </target_preparer> <option name="test-tag" value="FrameworksServicesTests" /> Loading
services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java +132 −0 Original line number Diff line number Diff line Loading @@ -19,20 +19,34 @@ package com.android.server.am; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.support.test.uiautomator.UiDevice; import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * Tests for {@link ActivityManager}. Loading @@ -43,12 +57,22 @@ import java.util.List; @FlakyTest(detail = "Promote to presubmit if stable") @Presubmit public class ActivityManagerTest { private static final String TAG = "ActivityManagerTest"; private static final String TEST_APP = "com.android.servicestests.apps.simpleservicetestapp"; private static final String TEST_CLASS = TEST_APP + ".SimpleService"; private static final int TEST_LOOPS = 100; private static final long AWAIT_TIMEOUT = 2000; private static final long CHECK_INTERVAL = 100; private IActivityManager mService; private IRemoteCallback mCallback; private Context mContext; @Before public void setUp() throws Exception { mService = ActivityManager.getService(); mContext = InstrumentationRegistry.getTargetContext(); } @Test Loading @@ -72,4 +96,112 @@ public class ActivityManagerTest { } } } @Test public void testServiceUnbindAndKilling() { for (int i = TEST_LOOPS; i > 0; i--) { runOnce(i); } } private void runOnce(long yieldDuration) { final PackageManager pm = mContext.getPackageManager(); int uid = 0; try { uid = pm.getPackageUid(TEST_APP, 0); } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException(e); } Intent intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); // Create a service connection with auto creation. CountDownLatch latch = new CountDownLatch(1); final MyServiceConnection autoConnection = new MyServiceConnection(latch); mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } // Create a service connection without any flags. intent = new Intent(); intent.setClassName(TEST_APP, TEST_CLASS); latch = new CountDownLatch(1); MyServiceConnection otherConnection = new MyServiceConnection(latch); mContext.bindService(intent, otherConnection, 0); try { assertTrue("Timeout to bind to service " + intent.getComponent(), latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Unable to bind to service " + intent.getComponent()); } // Inform the remote process to kill itself try { mCallback.sendResult(null); // It's basically a test for race condition, we expect the bringDownServiceLocked() // would find out the hosting process is dead - to do this, technically we should // do killing and unbinding simultaneously; but in reality, the killing would take // a little while, before the signal really kills it; so we do it in the same thread, // and even wait a while after sending killing signal. Thread.sleep(yieldDuration); } catch (RemoteException | InterruptedException e) { fail("Unable to kill the process"); } // Now unbind that auto connection, this should be equivalent to stopService mContext.unbindService(autoConnection); // Now we don't expect the system_server crashes. // Wait for the target process dies long total = 0; for (; total < AWAIT_TIMEOUT; total += CHECK_INTERVAL) { try { if (!targetPackageIsRunning(mContext, uid)) { break; } Thread.sleep(CHECK_INTERVAL); } catch (InterruptedException e) { } } assertTrue("Timeout to wait for the target package dies", total < AWAIT_TIMEOUT); mCallback = null; } private boolean targetPackageIsRunning(Context context, int uid) { final String result = runShellCommand( String.format("cmd activity get-uid-state %d", uid)); return !result.contains("(NONEXISTENT)"); } private static String runShellCommand(String cmd) { try { return UiDevice.getInstance( InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd); } catch (IOException e) { throw new RuntimeException(e); } } private class MyServiceConnection implements ServiceConnection { private CountDownLatch mLatch; MyServiceConnection(CountDownLatch latch) { this.mLatch = latch; } @Override public void onServiceConnected(ComponentName name, IBinder service) { mCallback = IRemoteCallback.Stub.asInterface(service); mLatch.countDown(); } @Override public void onServiceDisconnected(ComponentName name) { } } }
services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp 0 → 100644 +30 −0 Original line number Diff line number Diff line // 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. android_test_helper_app { name: "SimpleServiceTestApp", test_suites: ["device-tests"], srcs: ["**/*.java"], platform_apis: true, certificate: "platform", dex_preopt: { enabled: false, }, optimize: { enabled: false, }, }
services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml 0 → 100644 +25 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.servicestests.apps.simpleservicetestapp"> <application> <service android:name=".SimpleService" android:exported="true" /> </application> </manifest>
services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java 0 → 100644 +37 −0 Original line number Diff line number Diff line /* * 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.android.servicestests.apps.simpleservicetestapp; import android.app.Service; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.Process; public class SimpleService extends Service { private final IRemoteCallback.Stub mBinder = new IRemoteCallback.Stub() { @Override public void sendResult(Bundle bundle) { Process.killProcess(Process.myPid()); } }; @Override public IBinder onBind(Intent intent) { return mBinder; } }