Merge "Update ConnOnActivityStartTest to be hermetic." into oc-mr1-dev

This commit is contained in:
Sudheer Shanka
2017-08-10 22:52:40 +00:00
committed by Android (Google) Code Review
9 changed files with 112 additions and 212 deletions

View File

@@ -72,4 +72,6 @@ interface INetworkPolicyManager {
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
void factoryReset(String subscriber);
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
}

View File

@@ -435,4 +435,6 @@ interface INetworkManagementService
int removeRoutesFromLocalNetwork(in List<RouteInfo> routes);
void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges);
boolean isNetworkRestricted(int uid);
}

View File

@@ -2647,6 +2647,42 @@ public class NetworkManagementService extends INetworkManagementService.Stub
return failures;
}
@Override
public boolean isNetworkRestricted(int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
return isNetworkRestrictedInternal(uid);
}
private boolean isNetworkRestrictedInternal(int uid) {
synchronized (mRulesLock) {
if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
&& mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
return true;
}
if (getFirewallChainState(FIREWALL_CHAIN_DOZABLE)
&& mUidFirewallDozableRules.get(uid) != FIREWALL_RULE_ALLOW) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of device idle mode");
return true;
}
if (getFirewallChainState(FIREWALL_CHAIN_POWERSAVE)
&& mUidFirewallPowerSaveRules.get(uid) != FIREWALL_RULE_ALLOW) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
return true;
}
if (mUidRejectOnMetered.get(uid)) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
+ " in the background");
return true;
}
if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
return true;
}
return false;
}
}
private void setFirewallChainState(int chain, boolean state) {
synchronized (mRulesLock) {
mFirewallChainStates.put(chain, state);
@@ -2663,33 +2699,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
class LocalService extends NetworkManagementInternal {
@Override
public boolean isNetworkRestrictedForUid(int uid) {
synchronized (mRulesLock) {
if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
&& mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
return true;
}
if (getFirewallChainState(FIREWALL_CHAIN_DOZABLE)
&& mUidFirewallDozableRules.get(uid) != FIREWALL_RULE_ALLOW) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of device idle mode");
return true;
}
if (getFirewallChainState(FIREWALL_CHAIN_POWERSAVE)
&& mUidFirewallPowerSaveRules.get(uid) != FIREWALL_RULE_ALLOW) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
return true;
}
if (mUidRejectOnMetered.get(uid)) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
+ " in the background");
return true;
}
if (mDataSaverMode && !mUidAllowOnMetered.get(uid)) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of data saver mode");
return true;
}
return false;
}
return isNetworkRestrictedInternal(uid);
}
}

View File

@@ -4315,6 +4315,47 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
@Override
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
return isUidNetworkingBlockedInternal(uid, isNetworkMetered);
}
private boolean isUidNetworkingBlockedInternal(int uid, boolean isNetworkMetered) {
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_NONE);
isBackgroundRestricted = mRestrictBackground;
}
if (hasRule(uidRules, RULE_REJECT_ALL)) {
if (LOGV) logUidStatus(uid, "blocked by power restrictions");
return true;
}
if (!isNetworkMetered) {
if (LOGV) logUidStatus(uid, "allowed on unmetered network");
return false;
}
if (hasRule(uidRules, RULE_REJECT_METERED)) {
if (LOGV) logUidStatus(uid, "blacklisted on metered network");
return true;
}
if (hasRule(uidRules, RULE_ALLOW_METERED)) {
if (LOGV) logUidStatus(uid, "whitelisted on metered network");
return false;
}
if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
return false;
}
if (isBackgroundRestricted) {
if (LOGV) logUidStatus(uid, "blocked when background is restricted");
return true;
}
if (LOGV) logUidStatus(uid, "allowed by default");
return false;
}
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@Override
@@ -4352,42 +4393,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
@Override
public boolean isUidNetworkingBlocked(int uid, String ifname) {
final int uidRules;
final boolean isBackgroundRestricted;
final boolean isNetworkMetered;
synchronized (mUidRulesFirstLock) {
uidRules = mUidRules.get(uid, RULE_NONE);
isBackgroundRestricted = mRestrictBackground;
synchronized (mNetworkPoliciesSecondLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
synchronized (mNetworkPoliciesSecondLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
if (hasRule(uidRules, RULE_REJECT_ALL)) {
if (LOGV) logUidStatus(uid, "blocked by power restrictions");
return true;
}
if (!isNetworkMetered) {
if (LOGV) logUidStatus(uid, "allowed on unmetered network");
return false;
}
if (hasRule(uidRules, RULE_REJECT_METERED)) {
if (LOGV) logUidStatus(uid, "blacklisted on metered network");
return true;
}
if (hasRule(uidRules, RULE_ALLOW_METERED)) {
if (LOGV) logUidStatus(uid, "whitelisted on metered network");
return false;
}
if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
if (LOGV) logUidStatus(uid, "temporary whitelisted on metered network");
return false;
}
if (isBackgroundRestricted) {
if (LOGV) logUidStatus(uid, "blocked when background is restricted");
return true;
}
if (LOGV) logUidStatus(uid, "allowed by default");
return false;
return isUidNetworkingBlockedInternal(uid, isNetworkMetered);
}
}

View File

@@ -20,7 +20,6 @@ import static android.util.DebugUtils.valueToString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -37,8 +36,6 @@ import android.content.IntentSender;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Bundle;
@@ -101,19 +98,16 @@ public class ConnOnActivityStartTest {
private static final long WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
private static final long NETWORK_CHECK_TIMEOUT_MS = 6000; // 6 sec
private static final long NETWORK_CHECK_TIMEOUT_MS = 4000; // 4 sec
private static final long 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;
private static BatteryManager mBatteryManager;
private static ConnectivityManager mConnectivityManager;
@BeforeClass
public static void setUpOnce() throws Exception {
@@ -126,8 +120,6 @@ public class ConnOnActivityStartTest {
mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
}
@AfterClass
@@ -144,9 +136,6 @@ public class ConnOnActivityStartTest {
@Test
public void testStartActivity_batterySaver() throws Exception {
if (!isNetworkAvailable()) {
fail("Device doesn't have network connectivity");
}
setBatterySaverMode(true);
try {
testConnOnActivityStart("testStartActivity_batterySaver");
@@ -157,9 +146,6 @@ public class ConnOnActivityStartTest {
@Test
public void testStartActivity_dataSaver() throws Exception {
if (!isNetworkAvailable()) {
fail("Device doesn't have network connectivity");
}
setDataSaverMode(true);
try {
testConnOnActivityStart("testStartActivity_dataSaver");
@@ -170,9 +156,6 @@ public class ConnOnActivityStartTest {
@Test
public void testStartActivity_dozeMode() throws Exception {
if (!isNetworkAvailable()) {
fail("Device doesn't have network connectivity");
}
setDozeMode(true);
try {
testConnOnActivityStart("testStartActivity_dozeMode");
@@ -183,9 +166,6 @@ public class ConnOnActivityStartTest {
@Test
public void testStartActivity_appStandby() throws Exception {
if (!isNetworkAvailable()) {
fail("Device doesn't have network connectivity");
}
try{
turnBatteryOff();
setAppIdle(true);
@@ -200,9 +180,6 @@ public class ConnOnActivityStartTest {
@Test
public void testStartActivity_backgroundRestrict() throws Exception {
if (!isNetworkAvailable()) {
fail("Device doesn't have network connectivity");
}
updateRestrictBackgroundBlacklist(true);
try {
testConnOnActivityStart("testStartActivity_backgroundRestrict");
@@ -347,11 +324,6 @@ public class ConnOnActivityStartTest {
+ maxTries + " attempts. Last result: '" + result + "'");
}
private boolean isNetworkAvailable() throws Exception {
final NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
private void startActivityAndCheckNetworkAccess() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
final Intent launchIntent = new Intent().setComponent(
@@ -361,15 +333,15 @@ public class ConnOnActivityStartTest {
extras.putBinder(EXTRA_NETWORK_STATE_OBSERVER, new INetworkStateObserver.Stub() {
@Override
public void onNetworkStateChecked(String resultData) {
errors[0] = checkForAvailability(resultData);
errors[0] = 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);
if (errors[0] != null) {
fail("Network not available for test app " + mTestPkgUid + ". " + errors[0]);
}
} else {
fail("Timed out waiting for network availability status from test app " + mTestPkgUid);
@@ -381,43 +353,6 @@ public class ConnOnActivityStartTest {
.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};

View File

@@ -17,7 +17,6 @@ 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)

View File

@@ -17,8 +17,9 @@
<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" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<application>
<activity android:name=".ConnTestActivity"

View File

@@ -21,19 +21,17 @@ 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.net.INetworkPolicyManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.INetworkManagementService;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
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();
@@ -41,10 +39,6 @@ public class ConnTestActivity extends Activity {
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
@@ -84,7 +78,7 @@ public class ConnTestActivity extends Activity {
if (observer != null) {
AsyncTask.execute(() -> {
try {
observer.onNetworkStateChecked(checkNetworkStatus(ConnTestActivity.this));
observer.onNetworkStateChecked(checkNetworkStatus());
} catch (RemoteException e) {
Log.e(TAG, "Error occured while notifying the observer: " + e);
}
@@ -93,78 +87,25 @@ public class ConnTestActivity extends Activity {
}
/**
* Checks whether the network is available and return a string which can then be send as a
* result data for the ordered broadcast.
* Checks whether the network is restricted.
*
* <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>
* @return null if network is not restricted, otherwise an error message.
*/
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";
private String checkNetworkStatus() {
final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
final INetworkPolicyManager npms = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
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);
final boolean restrictedByFwRules = nms.isNetworkRestricted(Process.myUid());
final boolean restrictedByUidRules = npms.isUidNetworkingBlocked(Process.myUid(), true);
if (restrictedByFwRules || restrictedByUidRules) {
return "Network is restricted by fwRules: " + restrictedByFwRules
+ " and uidRules: " + restrictedByUidRules;
}
return null;
} catch (RemoteException e) {
return "Error talking to system server: " + e;
}
}
}