Merge "Add tests for verifying network availability on activity start." into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e78467f671
@@ -27,6 +27,10 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
|
|||||||
ShortcutManagerTestUtils \
|
ShortcutManagerTestUtils \
|
||||||
truth-prebuilt
|
truth-prebuilt
|
||||||
|
|
||||||
|
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
|
||||||
|
|
||||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||||
|
|
||||||
LOCAL_PACKAGE_NAME := FrameworksServicesTests
|
LOCAL_PACKAGE_NAME := FrameworksServicesTests
|
||||||
|
|||||||
@@ -48,6 +48,8 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
|
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
|
||||||
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
|
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<uses-library android:name="android.test.runner" />
|
<uses-library android:name="android.test.runner" />
|
||||||
|
|||||||
23
services/tests/servicestests/aidl/Android.mk
Normal file
23
services/tests/servicestests/aidl/Android.mk
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Copyright (C) 2017 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.
|
||||||
|
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
com/android/servicestests/aidl/INetworkStateObserver.aidl
|
||||||
|
LOCAL_MODULE := servicestests-aidl
|
||||||
|
include $(BUILD_STATIC_JAVA_LIBRARY)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.aidl;
|
||||||
|
|
||||||
|
oneway interface INetworkStateObserver {
|
||||||
|
/**
|
||||||
|
* {@param resultData} will be in the format
|
||||||
|
* NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo.
|
||||||
|
* For detailed info, see
|
||||||
|
* servicestests/test-apps/ConnTestApp/.../ConnTestActivity#checkNetworkStatus
|
||||||
|
*/
|
||||||
|
void onNetworkStateChecked(String resultData);
|
||||||
|
}
|
||||||
BIN
services/tests/servicestests/res/raw/conntestapp
Normal file
BIN
services/tests/servicestests/res/raw/conntestapp
Normal file
Binary file not shown.
@@ -0,0 +1,443 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.server.net;
|
||||||
|
|
||||||
|
import static android.util.DebugUtils.valueToString;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.android.frameworks.servicestests.R;
|
||||||
|
import com.android.servicestests.aidl.INetworkStateObserver;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.IntentSender;
|
||||||
|
import android.content.pm.IPackageDeleteObserver;
|
||||||
|
import android.content.pm.PackageInstaller;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.filters.LargeTest;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.support.test.uiautomator.UiDevice;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for verifying network availability on activity start.
|
||||||
|
*
|
||||||
|
* To run the tests, use
|
||||||
|
*
|
||||||
|
* runtest -c com.android.server.net.ConnOnActivityStartTest frameworks-services
|
||||||
|
*
|
||||||
|
* or the following steps:
|
||||||
|
*
|
||||||
|
* Build: m FrameworksServicesTests
|
||||||
|
* Install: adb install -r \
|
||||||
|
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
|
||||||
|
* Run: adb shell am instrument -e class com.android.server.net.ConnOnActivityStartTest -w \
|
||||||
|
* com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
|
||||||
|
*/
|
||||||
|
@LargeTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ConnOnActivityStartTest {
|
||||||
|
private static final String TAG = ConnOnActivityStartTest.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final String ACTION_INSTALL_COMPLETE = "com.android.server.net.INSTALL_COMPLETE";
|
||||||
|
|
||||||
|
private static final String TEST_APP_URI =
|
||||||
|
"android.resource://com.android.frameworks.servicestests/raw/conntestapp";
|
||||||
|
private static final String TEST_PKG = "com.android.servicestests.apps.conntestapp";
|
||||||
|
private static final String TEST_ACTIVITY_CLASS = TEST_PKG + ".ConnTestActivity";
|
||||||
|
|
||||||
|
private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
|
||||||
|
|
||||||
|
private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
|
||||||
|
|
||||||
|
private static final int WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
|
||||||
|
|
||||||
|
private static final int NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
|
||||||
|
|
||||||
|
private static final int SCREEN_ON_DELAY_MS = 500; // 0.5 sec
|
||||||
|
|
||||||
|
private static final String NETWORK_STATUS_SEPARATOR = "\\|";
|
||||||
|
|
||||||
|
private static final int REPEAT_TEST_COUNT = 5;
|
||||||
|
|
||||||
|
private static Context mContext;
|
||||||
|
private static UiDevice mUiDevice;
|
||||||
|
private static int mTestPkgUid;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpOnce() throws Exception {
|
||||||
|
mContext = InstrumentationRegistry.getContext();
|
||||||
|
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
|
||||||
|
|
||||||
|
installAppAndAssertInstalled();
|
||||||
|
mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
|
||||||
|
mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownOnce() {
|
||||||
|
mContext.getPackageManager().deletePackage(TEST_PKG,
|
||||||
|
new IPackageDeleteObserver.Stub() {
|
||||||
|
@Override
|
||||||
|
public void packageDeleted(String packageName, int returnCode)
|
||||||
|
throws RemoteException {
|
||||||
|
Log.e(TAG, packageName + " deleted, returnCode: " + returnCode);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartActivity_batterySaver() throws Exception {
|
||||||
|
setBatterySaverMode(true);
|
||||||
|
try {
|
||||||
|
testConnOnActivityStart("testStartActivity_batterySaver");
|
||||||
|
} finally {
|
||||||
|
setBatterySaverMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartActivity_dataSaver() throws Exception {
|
||||||
|
setDataSaverMode(true);
|
||||||
|
try {
|
||||||
|
testConnOnActivityStart("testStartActivity_dataSaver");
|
||||||
|
} finally {
|
||||||
|
setDataSaverMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartActivity_dozeMode() throws Exception {
|
||||||
|
setDozeMode(true);
|
||||||
|
try {
|
||||||
|
testConnOnActivityStart("testStartActivity_dozeMode");
|
||||||
|
} finally {
|
||||||
|
setDozeMode(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartActivity_appStandby() throws Exception {
|
||||||
|
try{
|
||||||
|
turnBatteryOff();
|
||||||
|
setAppIdle(true);
|
||||||
|
SystemClock.sleep(30000);
|
||||||
|
turnScreenOn();
|
||||||
|
startActivityAndCheckNetworkAccess();
|
||||||
|
} finally {
|
||||||
|
turnBatteryOn();
|
||||||
|
setAppIdle(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartActivity_backgroundRestrict() throws Exception {
|
||||||
|
updateRestrictBackgroundBlacklist(true);
|
||||||
|
try {
|
||||||
|
testConnOnActivityStart("testStartActivity_backgroundRestrict");
|
||||||
|
} finally {
|
||||||
|
updateRestrictBackgroundBlacklist(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testConnOnActivityStart(String testName) throws Exception {
|
||||||
|
for (int i = 1; i <= REPEAT_TEST_COUNT; ++i) {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, testName + " Start #" + i);
|
||||||
|
turnScreenOn();
|
||||||
|
SystemClock.sleep(SCREEN_ON_DELAY_MS);
|
||||||
|
startActivityAndCheckNetworkAccess();
|
||||||
|
Log.d(TAG, testName + " end #" + i);
|
||||||
|
} finally {
|
||||||
|
finishActivity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Some of these methods are also used in CTS, so instead of duplicating code,
|
||||||
|
// create a static library which can be used by both servicestests and cts.
|
||||||
|
private void setBatterySaverMode(boolean enabled) throws Exception {
|
||||||
|
if (enabled) {
|
||||||
|
turnBatteryOff();
|
||||||
|
executeCommand("settings put global low_power 1");
|
||||||
|
} else {
|
||||||
|
executeCommand("settings put global low_power 0");
|
||||||
|
turnBatteryOn();
|
||||||
|
}
|
||||||
|
final String result = executeCommand("settings get global low_power");
|
||||||
|
assertEquals(enabled ? "1" : "0", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDataSaverMode(boolean enabled) throws Exception {
|
||||||
|
executeCommand("cmd netpolicy set restrict-background " + enabled);
|
||||||
|
final String output = executeCommand("cmd netpolicy get restrict-background");
|
||||||
|
final String expectedSuffix = enabled ? "enabled" : "disabled";
|
||||||
|
assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
|
||||||
|
output.endsWith(expectedSuffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDozeMode(boolean enabled) throws Exception {
|
||||||
|
if (enabled) {
|
||||||
|
turnBatteryOff();
|
||||||
|
turnScreenOff();
|
||||||
|
executeCommand("dumpsys deviceidle force-idle deep");
|
||||||
|
} else {
|
||||||
|
turnScreenOn();
|
||||||
|
turnBatteryOn();
|
||||||
|
executeCommand("dumpsys deviceidle unforce");
|
||||||
|
}
|
||||||
|
assertDelayedCommandResult("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE",
|
||||||
|
5 /* maxTries */, 500 /* napTimeMs */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAppIdle(boolean enabled) throws Exception {
|
||||||
|
executeCommand("am set-inactive " + TEST_PKG + " " + enabled);
|
||||||
|
assertDelayedCommandResult("am get-inactive " + TEST_PKG, "Idle=" + enabled,
|
||||||
|
10 /* maxTries */, 2000 /* napTimeMs */);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRestrictBackgroundBlacklist(boolean add) throws Exception {
|
||||||
|
if (add) {
|
||||||
|
executeCommand("cmd netpolicy add restrict-background-blacklist " + mTestPkgUid);
|
||||||
|
} else {
|
||||||
|
executeCommand("cmd netpolicy remove restrict-background-blacklist " + mTestPkgUid);
|
||||||
|
}
|
||||||
|
assertRestrictBackground("restrict-background-blacklist", mTestPkgUid, add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
|
||||||
|
final int maxTries = 5;
|
||||||
|
boolean actual = false;
|
||||||
|
final String expectedUid = Integer.toString(uid);
|
||||||
|
String uids = "";
|
||||||
|
for (int i = 1; i <= maxTries; i++) {
|
||||||
|
final String output = executeCommand("cmd netpolicy list " + list);
|
||||||
|
uids = output.split(":")[1];
|
||||||
|
for (String candidate : uids.split(" ")) {
|
||||||
|
actual = candidate.trim().equals(expectedUid);
|
||||||
|
if (expected == actual) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
|
||||||
|
+ expected + ", got " + actual + "); sleeping 1s before polling again");
|
||||||
|
SystemClock.sleep(1000);
|
||||||
|
}
|
||||||
|
fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
|
||||||
|
+ ". Full list: " + uids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void turnBatteryOff() throws Exception {
|
||||||
|
executeCommand("cmd battery unplug");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void turnBatteryOn() throws Exception {
|
||||||
|
executeCommand("cmd battery reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void turnScreenOff() throws Exception {
|
||||||
|
executeCommand("input keyevent KEYCODE_SLEEP");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void turnScreenOn() throws Exception {
|
||||||
|
executeCommand("input keyevent KEYCODE_WAKEUP");
|
||||||
|
executeCommand("wm dismiss-keyguard");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String executeCommand(String cmd) throws IOException {
|
||||||
|
final String result = mUiDevice.executeShellCommand(cmd).trim();
|
||||||
|
Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertDelayedCommandResult(String cmd, String expectedResult,
|
||||||
|
int maxTries, int napTimeMs) throws IOException {
|
||||||
|
String result = "";
|
||||||
|
for (int i = 1; i <= maxTries; ++i) {
|
||||||
|
result = executeCommand(cmd);
|
||||||
|
if (expectedResult.equals(result)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.v(TAG, "Command '" + cmd + "' returned '" + result + " instead of '"
|
||||||
|
+ expectedResult + "' on attempt #" + i
|
||||||
|
+ "; sleeping " + napTimeMs + "ms before trying again");
|
||||||
|
SystemClock.sleep(napTimeMs);
|
||||||
|
}
|
||||||
|
fail("Command '" + cmd + "' did not return '" + expectedResult + "' after "
|
||||||
|
+ maxTries + " attempts. Last result: '" + result + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startActivityAndCheckNetworkAccess() throws Exception {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
final Intent launchIntent = new Intent().setComponent(
|
||||||
|
new ComponentName(TEST_PKG, TEST_ACTIVITY_CLASS));
|
||||||
|
final Bundle extras = new Bundle();
|
||||||
|
final String[] errors = new String[] {null};
|
||||||
|
extras.putBinder(EXTRA_NETWORK_STATE_OBSERVER, new INetworkStateObserver.Stub() {
|
||||||
|
@Override
|
||||||
|
public void onNetworkStateChecked(String resultData) {
|
||||||
|
errors[0] = checkForAvailability(resultData);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
launchIntent.putExtras(extras);
|
||||||
|
mContext.startActivity(launchIntent);
|
||||||
|
if (latch.await(NETWORK_CHECK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
|
||||||
|
if (!errors[0].isEmpty()) {
|
||||||
|
fail("Network not available for test app " + mTestPkgUid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("Timed out waiting for network availability status from test app " + mTestPkgUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishActivity() {
|
||||||
|
final Intent finishIntent = new Intent(ACTION_FINISH_ACTIVITY)
|
||||||
|
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||||
|
mContext.sendBroadcast(finishIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String checkForAvailability(String resultData) {
|
||||||
|
if (resultData == null) {
|
||||||
|
assertNotNull("Network status from app2 is null, Uid: " + mTestPkgUid, resultData);
|
||||||
|
}
|
||||||
|
// Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
|
||||||
|
final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
|
||||||
|
assertEquals("Wrong network status: " + resultData + ", Uid: " + mTestPkgUid,
|
||||||
|
5, parts.length); // Sanity check
|
||||||
|
final NetworkInfo.State state = parts[0].equals("null")
|
||||||
|
? null : NetworkInfo.State.valueOf(parts[0]);
|
||||||
|
final NetworkInfo.DetailedState detailedState = parts[1].equals("null")
|
||||||
|
? null : NetworkInfo.DetailedState.valueOf(parts[1]);
|
||||||
|
final boolean connected = Boolean.valueOf(parts[2]);
|
||||||
|
final String connectionCheckDetails = parts[3];
|
||||||
|
final String networkInfo = parts[4];
|
||||||
|
|
||||||
|
final StringBuilder errors = new StringBuilder();
|
||||||
|
final NetworkInfo.State expectedState = NetworkInfo.State.CONNECTED;
|
||||||
|
final NetworkInfo.DetailedState expectedDetailedState = NetworkInfo.DetailedState.CONNECTED;
|
||||||
|
|
||||||
|
if (true != connected) {
|
||||||
|
errors.append(String.format("External site connection failed: expected %s, got %s\n",
|
||||||
|
true, connected));
|
||||||
|
}
|
||||||
|
if (expectedState != state || expectedDetailedState != detailedState) {
|
||||||
|
errors.append(String.format("Connection state mismatch: expected %s/%s, got %s/%s\n",
|
||||||
|
expectedState, expectedDetailedState, state, detailedState));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length() > 0) {
|
||||||
|
errors.append("\tnetworkInfo: " + networkInfo + "\n");
|
||||||
|
errors.append("\tconnectionCheckDetails: " + connectionCheckDetails + "\n");
|
||||||
|
}
|
||||||
|
return errors.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void installAppAndAssertInstalled() throws Exception {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
final int[] result = {PackageInstaller.STATUS_SUCCESS};
|
||||||
|
final BroadcastReceiver installStatusReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
final String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
|
||||||
|
if (!TEST_PKG.equals(pkgName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result[0] = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
|
||||||
|
PackageInstaller.STATUS_FAILURE);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mContext.registerReceiver(installStatusReceiver, new IntentFilter(ACTION_INSTALL_COMPLETE));
|
||||||
|
try {
|
||||||
|
installApp();
|
||||||
|
if (latch.await(WAIT_FOR_INSTALL_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
|
||||||
|
if (result[0] != PackageInstaller.STATUS_SUCCESS) {
|
||||||
|
fail("Couldn't install test app, result: "
|
||||||
|
+ valueToString(PackageInstaller.class, "STATUS_", result[0]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("Timed out waiting for the test app to install");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mContext.unregisterReceiver(installStatusReceiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void installApp() throws Exception {
|
||||||
|
final Uri packageUri = Uri.parse(TEST_APP_URI);
|
||||||
|
final InputStream in = mContext.getContentResolver().openInputStream(packageUri);
|
||||||
|
|
||||||
|
final PackageInstaller packageInstaller
|
||||||
|
= mContext.getPackageManager().getPackageInstaller();
|
||||||
|
final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
|
||||||
|
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
|
||||||
|
params.setAppPackageName(TEST_PKG);
|
||||||
|
|
||||||
|
final int sessionId = packageInstaller.createSession(params);
|
||||||
|
final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
|
||||||
|
|
||||||
|
OutputStream out = null;
|
||||||
|
try {
|
||||||
|
out = session.openWrite(TAG, 0, -1);
|
||||||
|
final byte[] buffer = new byte[65536];
|
||||||
|
int c;
|
||||||
|
while ((c = in.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, c);
|
||||||
|
}
|
||||||
|
session.fsync(out);
|
||||||
|
} finally {
|
||||||
|
IoUtils.closeQuietly(in);
|
||||||
|
IoUtils.closeQuietly(out);
|
||||||
|
}
|
||||||
|
session.commit(createIntentSender(mContext, sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntentSender createIntentSender(Context context, int sessionId) {
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(
|
||||||
|
context, sessionId, new Intent(ACTION_INSTALL_COMPLETE), 0);
|
||||||
|
return pendingIntent.getIntentSender();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Copyright (C) 2017 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.
|
||||||
|
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
|
||||||
|
LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
|
||||||
|
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := ConnTestApp
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
LOCAL_DEX_PREOPT := false
|
||||||
|
LOCAL_PROGUARD_ENABLED := disabled
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2017 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.conntestapp">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<application>
|
||||||
|
<activity android:name=".ConnTestActivity"
|
||||||
|
android:exported="true" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.conntestapp;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.servicestests.aidl.INetworkStateObserver;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class ConnTestActivity extends Activity {
|
||||||
|
private static final String TAG = ConnTestActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final String TEST_PKG = ConnTestActivity.class.getPackage().getName();
|
||||||
|
private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
|
||||||
|
private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
|
||||||
|
|
||||||
|
private static final int NETWORK_TIMEOUT_MS = 5 * 1000;
|
||||||
|
|
||||||
|
private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
|
||||||
|
|
||||||
|
private BroadcastReceiver finishCommandReceiver = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
notifyNetworkStateObserver();
|
||||||
|
|
||||||
|
finishCommandReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
ConnTestActivity.this.finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
if (finishCommandReceiver != null) {
|
||||||
|
unregisterReceiver(finishCommandReceiver);
|
||||||
|
}
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyNetworkStateObserver() {
|
||||||
|
if (getIntent() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Bundle extras = getIntent().getExtras();
|
||||||
|
if (extras == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
|
||||||
|
extras.getBinder(EXTRA_NETWORK_STATE_OBSERVER));
|
||||||
|
if (observer != null) {
|
||||||
|
AsyncTask.execute(() -> {
|
||||||
|
try {
|
||||||
|
observer.onNetworkStateChecked(checkNetworkStatus(ConnTestActivity.this));
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Error occured while notifying the observer: " + e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the network is available and return a string which can then be send as a
|
||||||
|
* result data for the ordered broadcast.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The string has the following format:
|
||||||
|
*
|
||||||
|
* <p><pre><code>
|
||||||
|
* NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
|
||||||
|
* </code></pre>
|
||||||
|
*
|
||||||
|
* <p>Where:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
|
||||||
|
* <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
|
||||||
|
* <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
|
||||||
|
* to access an external website.
|
||||||
|
* <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
|
||||||
|
* connection attempt
|
||||||
|
* <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* For example, if the connection was established fine, the result would be something like:
|
||||||
|
* <p><pre><code>
|
||||||
|
* CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
|
||||||
|
* </code></pre>
|
||||||
|
*/
|
||||||
|
private String checkNetworkStatus(Context context) {
|
||||||
|
final ConnectivityManager cm =
|
||||||
|
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
final String address = "http://example.com";
|
||||||
|
final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
||||||
|
Log.d(TAG, "Running checkNetworkStatus() on thread "
|
||||||
|
+ Thread.currentThread().getName() + " for UID " + getUid(context)
|
||||||
|
+ "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
|
||||||
|
boolean checkStatus = false;
|
||||||
|
String checkDetails = "N/A";
|
||||||
|
try {
|
||||||
|
final URL url = new URL(address);
|
||||||
|
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn.setReadTimeout(NETWORK_TIMEOUT_MS);
|
||||||
|
conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
|
||||||
|
conn.setRequestMethod("GET");
|
||||||
|
conn.setDoInput(true);
|
||||||
|
conn.connect();
|
||||||
|
final int response = conn.getResponseCode();
|
||||||
|
checkStatus = true;
|
||||||
|
checkDetails = "HTTP response for " + address + ": " + response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
checkStatus = false;
|
||||||
|
checkDetails = "Exception getting " + address + ": " + e;
|
||||||
|
}
|
||||||
|
Log.d(TAG, checkDetails);
|
||||||
|
final String state, detailedState;
|
||||||
|
if (networkInfo != null) {
|
||||||
|
state = networkInfo.getState().name();
|
||||||
|
detailedState = networkInfo.getDetailedState().name();
|
||||||
|
} else {
|
||||||
|
state = detailedState = "null";
|
||||||
|
}
|
||||||
|
final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
|
||||||
|
Boolean.valueOf(checkStatus), checkDetails, networkInfo);
|
||||||
|
Log.d(TAG, "Offering " + status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getUid(Context context) {
|
||||||
|
final String packageName = context.getPackageName();
|
||||||
|
try {
|
||||||
|
return context.getPackageManager().getPackageUid(packageName, 0);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
throw new IllegalStateException("Could not get UID for " + packageName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user