Implement INetworkMonitorCallbacks#notifyNetworkTestedWithExtras.
INetworkMonitorCallbacks defines notifyNetworkTestedWithExtras() for notifying ConnectivityService of networks being tested along with a PersistableBundle of extras. A new event is introduced for NetworkStateTrackerHandler to notify the ConnectivityDiagnosticsHandler before continuing with the normal processing for "network tested" notifications. The event is also used in the ConnectivityDiagnosticsHandler. Bug: 143187964 Bug: 147391402 Test: compiles. Test: atest CtsNetTestCases FrameworksNetTests Change-Id: Iab29da790c0f5faae68227770bc3a84bbc94f124 (cherry picked from commit c5326407d592490783259a48a8ca653c4ff13122)
This commit is contained in:
@@ -676,7 +676,8 @@ public class ConnectivityDiagnosticsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mService.registerConnectivityDiagnosticsCallback(binder, request);
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
|
binder, request, mContext.getOpPackageName());
|
||||||
} catch (RemoteException exception) {
|
} catch (RemoteException exception) {
|
||||||
exception.rethrowFromSystemServer();
|
exception.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ interface IConnectivityManager
|
|||||||
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
|
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
|
||||||
|
|
||||||
void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
|
void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
|
||||||
in NetworkRequest request);
|
in NetworkRequest request, String callingPackageName);
|
||||||
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
|
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
|
||||||
|
|
||||||
IBinder startOrGetTestNetworkService();
|
IBinder startOrGetTestNetworkService();
|
||||||
|
|||||||
@@ -858,8 +858,8 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
*
|
*
|
||||||
* <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
|
* <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
|
||||||
*
|
*
|
||||||
* <p>An app is granted owner privileges over Networks that it supplies. Owner privileges
|
* <p>An app is granted owner privileges over Networks that it supplies. The owner UID MUST
|
||||||
* implicitly include administrator privileges.
|
* always be included in administratorUids.
|
||||||
*
|
*
|
||||||
* @param administratorUids the UIDs to be set as administrators of this Network.
|
* @param administratorUids the UIDs to be set as administrators of this Network.
|
||||||
* @hide
|
* @hide
|
||||||
|
|||||||
@@ -48,8 +48,11 @@ import static android.os.Process.INVALID_UID;
|
|||||||
import static android.system.OsConstants.IPPROTO_TCP;
|
import static android.system.OsConstants.IPPROTO_TCP;
|
||||||
import static android.system.OsConstants.IPPROTO_UDP;
|
import static android.system.OsConstants.IPPROTO_UDP;
|
||||||
|
|
||||||
|
import static java.util.Map.Entry;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.app.AppOpsManager;
|
||||||
import android.app.BroadcastOptions;
|
import android.app.BroadcastOptions;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
@@ -62,6 +65,7 @@ import android.content.res.Configuration;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.net.CaptivePortal;
|
import android.net.CaptivePortal;
|
||||||
import android.net.ConnectionInfo;
|
import android.net.ConnectionInfo;
|
||||||
|
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.ICaptivePortal;
|
import android.net.ICaptivePortal;
|
||||||
import android.net.IConnectivityDiagnosticsCallback;
|
import android.net.IConnectivityDiagnosticsCallback;
|
||||||
@@ -130,6 +134,7 @@ import android.os.Message;
|
|||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -170,6 +175,7 @@ import com.android.internal.util.ArrayUtils;
|
|||||||
import com.android.internal.util.AsyncChannel;
|
import com.android.internal.util.AsyncChannel;
|
||||||
import com.android.internal.util.DumpUtils;
|
import com.android.internal.util.DumpUtils;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
import com.android.internal.util.LocationPermissionChecker;
|
||||||
import com.android.internal.util.MessageUtils;
|
import com.android.internal.util.MessageUtils;
|
||||||
import com.android.internal.util.XmlUtils;
|
import com.android.internal.util.XmlUtils;
|
||||||
import com.android.server.am.BatteryStatsService;
|
import com.android.server.am.BatteryStatsService;
|
||||||
@@ -492,9 +498,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
/**
|
/**
|
||||||
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
|
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
|
||||||
* been tested.
|
* been tested.
|
||||||
* obj = String representing URL that Internet probe was redirect to, if it was redirected.
|
* obj = {@link NetworkTestedResults} representing information sent from NetworkMonitor.
|
||||||
* arg1 = One of the NETWORK_TESTED_RESULT_* constants.
|
* data = PersistableBundle of extras passed from NetworkMonitor. If {@link
|
||||||
* arg2 = NetID.
|
* NetworkMonitorCallbacks#notifyNetworkTested} is called, this will be null.
|
||||||
*/
|
*/
|
||||||
private static final int EVENT_NETWORK_TESTED = 41;
|
private static final int EVENT_NETWORK_TESTED = 41;
|
||||||
|
|
||||||
@@ -596,6 +602,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private Set<String> mWolSupportedInterfaces;
|
private Set<String> mWolSupportedInterfaces;
|
||||||
|
|
||||||
private TelephonyManager mTelephonyManager;
|
private TelephonyManager mTelephonyManager;
|
||||||
|
private final AppOpsManager mAppOpsManager;
|
||||||
|
|
||||||
|
private final LocationPermissionChecker mLocationPermissionChecker;
|
||||||
|
|
||||||
private KeepaliveTracker mKeepaliveTracker;
|
private KeepaliveTracker mKeepaliveTracker;
|
||||||
private NetworkNotificationManager mNotifier;
|
private NetworkNotificationManager mNotifier;
|
||||||
@@ -992,6 +1001,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mNetd = netd;
|
mNetd = netd;
|
||||||
mKeyStore = KeyStore.getInstance();
|
mKeyStore = KeyStore.getInstance();
|
||||||
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
|
||||||
|
|
||||||
// To ensure uid rules are synchronized with Network Policy, register for
|
// To ensure uid rules are synchronized with Network Policy, register for
|
||||||
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
|
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
|
||||||
@@ -2101,6 +2112,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
|
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkNetworkStackPermission(int pid, int uid) {
|
||||||
|
return checkAnyPermissionOf(pid, uid,
|
||||||
|
android.Manifest.permission.NETWORK_STACK,
|
||||||
|
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) {
|
private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) {
|
||||||
return checkAnyPermissionOf(pid, uid,
|
return checkAnyPermissionOf(pid, uid,
|
||||||
android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP,
|
android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP,
|
||||||
@@ -2747,88 +2764,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_NETWORK_TESTED: {
|
case EVENT_NETWORK_TESTED: {
|
||||||
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
|
final NetworkTestedResults results = (NetworkTestedResults) msg.obj;
|
||||||
|
|
||||||
|
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(results.mNetId);
|
||||||
if (nai == null) break;
|
if (nai == null) break;
|
||||||
|
|
||||||
final boolean wasPartial = nai.partialConnectivity;
|
handleNetworkTested(nai, results.mTestResult,
|
||||||
nai.partialConnectivity = ((msg.arg1 & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
|
(results.mRedirectUrl == null) ? "" : results.mRedirectUrl);
|
||||||
final boolean partialConnectivityChanged =
|
|
||||||
(wasPartial != nai.partialConnectivity);
|
|
||||||
|
|
||||||
final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0);
|
// Invoke ConnectivityReport generation for this Network test event.
|
||||||
final boolean wasValidated = nai.lastValidated;
|
final Message m =
|
||||||
final boolean wasDefault = isDefaultNetwork(nai);
|
mConnectivityDiagnosticsHandler.obtainMessage(
|
||||||
// Only show a connected notification if the network is pending validation
|
ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED,
|
||||||
// after the captive portal app was open, and it has now validated.
|
new ConnectivityReportEvent(results.mTimestampMillis, nai));
|
||||||
if (nai.captivePortalValidationPending && valid) {
|
m.setData(msg.getData());
|
||||||
// User is now logged in, network validated.
|
mConnectivityDiagnosticsHandler.sendMessage(m);
|
||||||
nai.captivePortalValidationPending = false;
|
|
||||||
showNetworkNotification(nai, NotificationType.LOGGED_IN);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
|
|
||||||
|
|
||||||
if (DBG) {
|
|
||||||
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
|
||||||
? " with redirect to " + redirectUrl
|
|
||||||
: "";
|
|
||||||
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
|
||||||
}
|
|
||||||
if (valid != nai.lastValidated) {
|
|
||||||
if (wasDefault) {
|
|
||||||
mDeps.getMetricsLogger()
|
|
||||||
.defaultNetworkMetrics().logDefaultNetworkValidity(
|
|
||||||
SystemClock.elapsedRealtime(), valid);
|
|
||||||
}
|
|
||||||
final int oldScore = nai.getCurrentScore();
|
|
||||||
nai.lastValidated = valid;
|
|
||||||
nai.everValidated |= valid;
|
|
||||||
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
|
||||||
// If score has changed, rebroadcast to NetworkProviders. b/17726566
|
|
||||||
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
|
|
||||||
if (valid) {
|
|
||||||
handleFreshlyValidatedNetwork(nai);
|
|
||||||
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
|
|
||||||
// LOST_INTERNET notifications if network becomes valid.
|
|
||||||
mNotifier.clearNotification(nai.network.netId,
|
|
||||||
NotificationType.NO_INTERNET);
|
|
||||||
mNotifier.clearNotification(nai.network.netId,
|
|
||||||
NotificationType.LOST_INTERNET);
|
|
||||||
mNotifier.clearNotification(nai.network.netId,
|
|
||||||
NotificationType.PARTIAL_CONNECTIVITY);
|
|
||||||
mNotifier.clearNotification(nai.network.netId,
|
|
||||||
NotificationType.PRIVATE_DNS_BROKEN);
|
|
||||||
// If network becomes valid, the hasShownBroken should be reset for
|
|
||||||
// that network so that the notification will be fired when the private
|
|
||||||
// DNS is broken again.
|
|
||||||
nai.networkAgentConfig.hasShownBroken = false;
|
|
||||||
}
|
|
||||||
} else if (partialConnectivityChanged) {
|
|
||||||
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
|
|
||||||
}
|
|
||||||
updateInetCondition(nai);
|
|
||||||
// Let the NetworkAgent know the state of its network
|
|
||||||
Bundle redirectUrlBundle = new Bundle();
|
|
||||||
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
|
|
||||||
// TODO: Evaluate to update partial connectivity to status to NetworkAgent.
|
|
||||||
nai.asyncChannel.sendMessage(
|
|
||||||
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
|
||||||
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
|
||||||
0, redirectUrlBundle);
|
|
||||||
|
|
||||||
// If NetworkMonitor detects partial connectivity before
|
|
||||||
// EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification
|
|
||||||
// immediately. Re-notify partial connectivity silently if no internet
|
|
||||||
// notification already there.
|
|
||||||
if (!wasPartial && nai.partialConnectivity) {
|
|
||||||
// Remove delayed message if there is a pending message.
|
|
||||||
mHandler.removeMessages(EVENT_PROMPT_UNVALIDATED, nai.network);
|
|
||||||
handlePromptUnvalidated(nai.network);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasValidated && !nai.lastValidated) {
|
|
||||||
handleNetworkUnvalidated(nai);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_PROVISIONING_NOTIFICATION: {
|
case EVENT_PROVISIONING_NOTIFICATION: {
|
||||||
@@ -2879,6 +2829,87 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleNetworkTested(
|
||||||
|
@NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) {
|
||||||
|
final boolean wasPartial = nai.partialConnectivity;
|
||||||
|
nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
|
||||||
|
final boolean partialConnectivityChanged =
|
||||||
|
(wasPartial != nai.partialConnectivity);
|
||||||
|
|
||||||
|
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
|
||||||
|
final boolean wasValidated = nai.lastValidated;
|
||||||
|
final boolean wasDefault = isDefaultNetwork(nai);
|
||||||
|
// Only show a connected notification if the network is pending validation
|
||||||
|
// after the captive portal app was open, and it has now validated.
|
||||||
|
if (nai.captivePortalValidationPending && valid) {
|
||||||
|
// User is now logged in, network validated.
|
||||||
|
nai.captivePortalValidationPending = false;
|
||||||
|
showNetworkNotification(nai, NotificationType.LOGGED_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG) {
|
||||||
|
final String logMsg = !TextUtils.isEmpty(redirectUrl)
|
||||||
|
? " with redirect to " + redirectUrl
|
||||||
|
: "";
|
||||||
|
log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
|
||||||
|
}
|
||||||
|
if (valid != nai.lastValidated) {
|
||||||
|
if (wasDefault) {
|
||||||
|
mDeps.getMetricsLogger()
|
||||||
|
.defaultNetworkMetrics().logDefaultNetworkValidity(
|
||||||
|
SystemClock.elapsedRealtime(), valid);
|
||||||
|
}
|
||||||
|
final int oldScore = nai.getCurrentScore();
|
||||||
|
nai.lastValidated = valid;
|
||||||
|
nai.everValidated |= valid;
|
||||||
|
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
||||||
|
// If score has changed, rebroadcast to NetworkProviders. b/17726566
|
||||||
|
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
|
||||||
|
if (valid) {
|
||||||
|
handleFreshlyValidatedNetwork(nai);
|
||||||
|
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
|
||||||
|
// LOST_INTERNET notifications if network becomes valid.
|
||||||
|
mNotifier.clearNotification(nai.network.netId,
|
||||||
|
NotificationType.NO_INTERNET);
|
||||||
|
mNotifier.clearNotification(nai.network.netId,
|
||||||
|
NotificationType.LOST_INTERNET);
|
||||||
|
mNotifier.clearNotification(nai.network.netId,
|
||||||
|
NotificationType.PARTIAL_CONNECTIVITY);
|
||||||
|
mNotifier.clearNotification(nai.network.netId,
|
||||||
|
NotificationType.PRIVATE_DNS_BROKEN);
|
||||||
|
// If network becomes valid, the hasShownBroken should be reset for
|
||||||
|
// that network so that the notification will be fired when the private
|
||||||
|
// DNS is broken again.
|
||||||
|
nai.networkAgentConfig.hasShownBroken = false;
|
||||||
|
}
|
||||||
|
} else if (partialConnectivityChanged) {
|
||||||
|
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
|
||||||
|
}
|
||||||
|
updateInetCondition(nai);
|
||||||
|
// Let the NetworkAgent know the state of its network
|
||||||
|
Bundle redirectUrlBundle = new Bundle();
|
||||||
|
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
|
||||||
|
// TODO: Evaluate to update partial connectivity to status to NetworkAgent.
|
||||||
|
nai.asyncChannel.sendMessage(
|
||||||
|
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
||||||
|
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
||||||
|
0, redirectUrlBundle);
|
||||||
|
|
||||||
|
// If NetworkMonitor detects partial connectivity before
|
||||||
|
// EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification
|
||||||
|
// immediately. Re-notify partial connectivity silently if no internet
|
||||||
|
// notification already there.
|
||||||
|
if (!wasPartial && nai.partialConnectivity) {
|
||||||
|
// Remove delayed message if there is a pending message.
|
||||||
|
mHandler.removeMessages(EVENT_PROMPT_UNVALIDATED, nai.network);
|
||||||
|
handlePromptUnvalidated(nai.network);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wasValidated && !nai.lastValidated) {
|
||||||
|
handleNetworkUnvalidated(nai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int getCaptivePortalMode() {
|
private int getCaptivePortalMode() {
|
||||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
Settings.Global.CAPTIVE_PORTAL_MODE,
|
Settings.Global.CAPTIVE_PORTAL_MODE,
|
||||||
@@ -2927,8 +2958,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
|
public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
|
||||||
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED,
|
notifyNetworkTestedWithExtras(testResult, redirectUrl, SystemClock.elapsedRealtime(),
|
||||||
testResult, mNetId, redirectUrl));
|
PersistableBundle.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyNetworkTestedWithExtras(
|
||||||
|
int testResult,
|
||||||
|
@Nullable String redirectUrl,
|
||||||
|
long timestampMillis,
|
||||||
|
@NonNull PersistableBundle extras) {
|
||||||
|
final Message msg =
|
||||||
|
mTrackerHandler.obtainMessage(
|
||||||
|
EVENT_NETWORK_TESTED,
|
||||||
|
new NetworkTestedResults(
|
||||||
|
mNetId, testResult, timestampMillis, redirectUrl));
|
||||||
|
msg.setData(new Bundle(extras));
|
||||||
|
mTrackerHandler.sendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -7359,7 +7405,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
@GuardedBy("mVpns")
|
@GuardedBy("mVpns")
|
||||||
private Vpn getVpnIfOwner() {
|
private Vpn getVpnIfOwner() {
|
||||||
final int uid = Binder.getCallingUid();
|
return getVpnIfOwner(Binder.getCallingUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mVpns")
|
||||||
|
private Vpn getVpnIfOwner(int uid) {
|
||||||
final int user = UserHandle.getUserId(uid);
|
final int user = UserHandle.getUserId(uid);
|
||||||
|
|
||||||
final Vpn vpn = mVpns.get(user);
|
final Vpn vpn = mVpns.get(user);
|
||||||
@@ -7471,6 +7521,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
*/
|
*/
|
||||||
private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2;
|
private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event for {@link NetworkStateTrackerHandler} to trigger ConnectivityReport callbacks
|
||||||
|
* after processing {@link #EVENT_NETWORK_TESTED} events.
|
||||||
|
* obj = {@link ConnectivityReportEvent} representing ConnectivityReport info reported from
|
||||||
|
* NetworkMonitor.
|
||||||
|
* data = PersistableBundle of extras passed from NetworkMonitor.
|
||||||
|
*
|
||||||
|
* <p>See {@link ConnectivityService#EVENT_NETWORK_TESTED}.
|
||||||
|
*/
|
||||||
|
private static final int EVENT_NETWORK_TESTED = ConnectivityService.EVENT_NETWORK_TESTED;
|
||||||
|
|
||||||
private ConnectivityDiagnosticsHandler(Looper looper) {
|
private ConnectivityDiagnosticsHandler(Looper looper) {
|
||||||
super(looper);
|
super(looper);
|
||||||
}
|
}
|
||||||
@@ -7488,6 +7549,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
(IConnectivityDiagnosticsCallback) msg.obj, msg.arg1);
|
(IConnectivityDiagnosticsCallback) msg.obj, msg.arg1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_NETWORK_TESTED: {
|
||||||
|
final ConnectivityReportEvent reportEvent =
|
||||||
|
(ConnectivityReportEvent) msg.obj;
|
||||||
|
|
||||||
|
// This is safe because {@link
|
||||||
|
// NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} receives a
|
||||||
|
// PersistableBundle and converts it to the Bundle in the incoming Message. If
|
||||||
|
// {@link NetworkMonitorCallbacks#notifyNetworkTested} is called, msg.data will
|
||||||
|
// not be set. This is also safe, as msg.getData() will return an empty Bundle.
|
||||||
|
final PersistableBundle extras = new PersistableBundle(msg.getData());
|
||||||
|
handleNetworkTestedWithExtras(reportEvent, extras);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7497,12 +7571,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient {
|
class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient {
|
||||||
@NonNull private final IConnectivityDiagnosticsCallback mCb;
|
@NonNull private final IConnectivityDiagnosticsCallback mCb;
|
||||||
@NonNull private final NetworkRequestInfo mRequestInfo;
|
@NonNull private final NetworkRequestInfo mRequestInfo;
|
||||||
|
@NonNull private final String mCallingPackageName;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ConnectivityDiagnosticsCallbackInfo(
|
ConnectivityDiagnosticsCallbackInfo(
|
||||||
@NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) {
|
@NonNull IConnectivityDiagnosticsCallback cb,
|
||||||
|
@NonNull NetworkRequestInfo nri,
|
||||||
|
@NonNull String callingPackageName) {
|
||||||
mCb = cb;
|
mCb = cb;
|
||||||
mRequestInfo = nri;
|
mRequestInfo = nri;
|
||||||
|
mCallingPackageName = callingPackageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -7512,6 +7590,39 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used for sending information from {@link
|
||||||
|
* NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} to the handler for processing it.
|
||||||
|
*/
|
||||||
|
private static class NetworkTestedResults {
|
||||||
|
private final int mNetId;
|
||||||
|
private final int mTestResult;
|
||||||
|
private final long mTimestampMillis;
|
||||||
|
@Nullable private final String mRedirectUrl;
|
||||||
|
|
||||||
|
private NetworkTestedResults(
|
||||||
|
int netId, int testResult, long timestampMillis, @Nullable String redirectUrl) {
|
||||||
|
mNetId = netId;
|
||||||
|
mTestResult = testResult;
|
||||||
|
mTimestampMillis = timestampMillis;
|
||||||
|
mRedirectUrl = redirectUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used for sending information from {@link NetworkStateTrackerHandler} to {@link
|
||||||
|
* ConnectivityDiagnosticsHandler}.
|
||||||
|
*/
|
||||||
|
private static class ConnectivityReportEvent {
|
||||||
|
private final long mTimestampMillis;
|
||||||
|
@NonNull private final NetworkAgentInfo mNai;
|
||||||
|
|
||||||
|
private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai) {
|
||||||
|
mTimestampMillis = timestampMillis;
|
||||||
|
mNai = nai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleRegisterConnectivityDiagnosticsCallback(
|
private void handleRegisterConnectivityDiagnosticsCallback(
|
||||||
@NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
|
@NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
|
||||||
ensureRunningOnConnectivityServiceThread();
|
ensureRunningOnConnectivityServiceThread();
|
||||||
@@ -7559,13 +7670,80 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0);
|
cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleNetworkTestedWithExtras(
|
||||||
|
@NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) {
|
||||||
|
final NetworkAgentInfo nai = reportEvent.mNai;
|
||||||
|
final ConnectivityReport report =
|
||||||
|
new ConnectivityReport(
|
||||||
|
reportEvent.mNai.network,
|
||||||
|
reportEvent.mTimestampMillis,
|
||||||
|
nai.linkProperties,
|
||||||
|
nai.networkCapabilities,
|
||||||
|
extras);
|
||||||
|
final List<IConnectivityDiagnosticsCallback> results =
|
||||||
|
getMatchingPermissionedCallbacks(nai);
|
||||||
|
for (final IConnectivityDiagnosticsCallback cb : results) {
|
||||||
|
try {
|
||||||
|
cb.onConnectivityReport(report);
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
loge("Error invoking onConnectivityReport", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
|
||||||
|
@NonNull NetworkAgentInfo nai) {
|
||||||
|
final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
|
||||||
|
for (Entry<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo> entry :
|
||||||
|
mConnectivityDiagnosticsCallbacks.entrySet()) {
|
||||||
|
final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
|
||||||
|
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
|
||||||
|
if (nai.satisfies(nri.request)) {
|
||||||
|
if (checkConnectivityDiagnosticsPermissions(
|
||||||
|
nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
|
||||||
|
results.add(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean checkConnectivityDiagnosticsPermissions(
|
||||||
|
int callbackPid, int callbackUid, NetworkAgentInfo nai, String callbackPackageName) {
|
||||||
|
if (checkNetworkStackPermission(callbackPid, callbackUid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mLocationPermissionChecker.checkLocationPermission(
|
||||||
|
callbackPackageName, null /* featureId */, callbackUid, null /* message */)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (mVpns) {
|
||||||
|
if (getVpnIfOwner(callbackUid) != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Administrator UIDs also contains the Owner UID
|
||||||
|
if (nai.networkCapabilities.getAdministratorUids().contains(callbackUid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerConnectivityDiagnosticsCallback(
|
public void registerConnectivityDiagnosticsCallback(
|
||||||
@NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) {
|
@NonNull IConnectivityDiagnosticsCallback callback,
|
||||||
|
@NonNull NetworkRequest request,
|
||||||
|
@NonNull String callingPackageName) {
|
||||||
if (request.legacyType != TYPE_NONE) {
|
if (request.legacyType != TYPE_NONE) {
|
||||||
throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
|
throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
|
||||||
+ " Please use NetworkCapabilities instead.");
|
+ " Please use NetworkCapabilities instead.");
|
||||||
}
|
}
|
||||||
|
mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
|
||||||
|
|
||||||
// This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
|
// This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
|
||||||
// and administrator uids to be safe.
|
// and administrator uids to be safe.
|
||||||
@@ -7583,7 +7761,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// callback's binder death.
|
// callback's binder death.
|
||||||
final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
|
final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
|
||||||
final ConnectivityDiagnosticsCallbackInfo cbInfo =
|
final ConnectivityDiagnosticsCallbackInfo cbInfo =
|
||||||
new ConnectivityDiagnosticsCallbackInfo(callback, nri);
|
new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
|
||||||
|
|
||||||
mConnectivityDiagnosticsHandler.sendMessage(
|
mConnectivityDiagnosticsHandler.sendMessage(
|
||||||
mConnectivityDiagnosticsHandler.obtainMessage(
|
mConnectivityDiagnosticsHandler.obtainMessage(
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -58,21 +60,26 @@ public class ConnectivityDiagnosticsManagerTest {
|
|||||||
|
|
||||||
private static final Executor INLINE_EXECUTOR = x -> x.run();
|
private static final Executor INLINE_EXECUTOR = x -> x.run();
|
||||||
|
|
||||||
@Mock private Context mContext;
|
|
||||||
@Mock private IConnectivityManager mService;
|
@Mock private IConnectivityManager mService;
|
||||||
@Mock private ConnectivityDiagnosticsCallback mCb;
|
@Mock private ConnectivityDiagnosticsCallback mCb;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
private ConnectivityDiagnosticsBinder mBinder;
|
private ConnectivityDiagnosticsBinder mBinder;
|
||||||
private ConnectivityDiagnosticsManager mManager;
|
private ConnectivityDiagnosticsManager mManager;
|
||||||
|
|
||||||
|
private String mPackageName;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = mock(Context.class);
|
mContext = InstrumentationRegistry.getContext();
|
||||||
|
|
||||||
mService = mock(IConnectivityManager.class);
|
mService = mock(IConnectivityManager.class);
|
||||||
mCb = mock(ConnectivityDiagnosticsCallback.class);
|
mCb = mock(ConnectivityDiagnosticsCallback.class);
|
||||||
|
|
||||||
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
|
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
|
||||||
mManager = new ConnectivityDiagnosticsManager(mContext, mService);
|
mManager = new ConnectivityDiagnosticsManager(mContext, mService);
|
||||||
|
|
||||||
|
mPackageName = mContext.getOpPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -271,7 +278,7 @@ public class ConnectivityDiagnosticsManagerTest {
|
|||||||
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
|
|
||||||
verify(mService).registerConnectivityDiagnosticsCallback(
|
verify(mService).registerConnectivityDiagnosticsCallback(
|
||||||
any(ConnectivityDiagnosticsBinder.class), eq(request));
|
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
|
||||||
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +309,7 @@ public class ConnectivityDiagnosticsManagerTest {
|
|||||||
// verify that re-registering is successful
|
// verify that re-registering is successful
|
||||||
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
|
||||||
verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
|
verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
|
||||||
any(ConnectivityDiagnosticsBinder.class), eq(request));
|
any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
|
||||||
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
|||||||
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
|
||||||
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
|
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
|
||||||
@@ -119,6 +120,7 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
|
import android.app.AppOpsManager;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -132,6 +134,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.location.LocationManager;
|
||||||
import android.net.CaptivePortalData;
|
import android.net.CaptivePortalData;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.ConnectivityManager.NetworkCallback;
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
@@ -177,6 +180,7 @@ import android.net.shared.PrivateDnsConfig;
|
|||||||
import android.net.util.MultinetworkPolicyTracker;
|
import android.net.util.MultinetworkPolicyTracker;
|
||||||
import android.os.BadParcelableException;
|
import android.os.BadParcelableException;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -187,6 +191,7 @@ import android.os.Looper;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -218,6 +223,7 @@ import com.android.server.connectivity.DefaultNetworkMetrics;
|
|||||||
import com.android.server.connectivity.IpConnectivityMetrics;
|
import com.android.server.connectivity.IpConnectivityMetrics;
|
||||||
import com.android.server.connectivity.MockableSystemProperties;
|
import com.android.server.connectivity.MockableSystemProperties;
|
||||||
import com.android.server.connectivity.Nat464Xlat;
|
import com.android.server.connectivity.Nat464Xlat;
|
||||||
|
import com.android.server.connectivity.NetworkAgentInfo;
|
||||||
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
|
||||||
import com.android.server.connectivity.ProxyTracker;
|
import com.android.server.connectivity.ProxyTracker;
|
||||||
import com.android.server.connectivity.Vpn;
|
import com.android.server.connectivity.Vpn;
|
||||||
@@ -292,6 +298,8 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
|
private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
|
||||||
|
|
||||||
|
private static final long TIMESTAMP = 1234L;
|
||||||
|
|
||||||
private static final String CLAT_PREFIX = "v4-";
|
private static final String CLAT_PREFIX = "v4-";
|
||||||
private static final String MOBILE_IFNAME = "test_rmnet_data0";
|
private static final String MOBILE_IFNAME = "test_rmnet_data0";
|
||||||
private static final String WIFI_IFNAME = "test_wlan0";
|
private static final String WIFI_IFNAME = "test_wlan0";
|
||||||
@@ -327,6 +335,8 @@ public class ConnectivityServiceTest {
|
|||||||
@Mock AlarmManager mAlarmManager;
|
@Mock AlarmManager mAlarmManager;
|
||||||
@Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
|
@Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
|
||||||
@Mock IBinder mIBinder;
|
@Mock IBinder mIBinder;
|
||||||
|
@Mock LocationManager mLocationManager;
|
||||||
|
@Mock AppOpsManager mAppOpsManager;
|
||||||
|
|
||||||
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
|
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
|
||||||
ArgumentCaptor.forClass(ResolverParamsParcel.class);
|
ArgumentCaptor.forClass(ResolverParamsParcel.class);
|
||||||
@@ -412,6 +422,8 @@ public class ConnectivityServiceTest {
|
|||||||
if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
|
if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
|
||||||
if (Context.USER_SERVICE.equals(name)) return mUserManager;
|
if (Context.USER_SERVICE.equals(name)) return mUserManager;
|
||||||
if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
|
if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
|
||||||
|
if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
|
||||||
|
if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
|
||||||
return super.getSystemService(name);
|
return super.getSystemService(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,6 +576,7 @@ public class ConnectivityServiceTest {
|
|||||||
private int mProbesCompleted;
|
private int mProbesCompleted;
|
||||||
private int mProbesSucceeded;
|
private int mProbesSucceeded;
|
||||||
private String mNmValidationRedirectUrl = null;
|
private String mNmValidationRedirectUrl = null;
|
||||||
|
private PersistableBundle mValidationExtras = PersistableBundle.EMPTY;
|
||||||
private boolean mNmProvNotificationRequested = false;
|
private boolean mNmProvNotificationRequested = false;
|
||||||
|
|
||||||
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
|
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
|
||||||
@@ -631,8 +644,8 @@ public class ConnectivityServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
|
mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
|
||||||
mNmCallbacks.notifyNetworkTested(
|
mNmCallbacks.notifyNetworkTestedWithExtras(
|
||||||
mNmValidationResult, mNmValidationRedirectUrl);
|
mNmValidationResult, mNmValidationRedirectUrl, TIMESTAMP, mValidationExtras);
|
||||||
|
|
||||||
if (mNmValidationRedirectUrl != null) {
|
if (mNmValidationRedirectUrl != null) {
|
||||||
mNmCallbacks.showProvisioningNotification(
|
mNmCallbacks.showProvisioningNotification(
|
||||||
@@ -970,6 +983,8 @@ public class ConnectivityServiceTest {
|
|||||||
// not inherit from NetworkAgent.
|
// not inherit from NetworkAgent.
|
||||||
private TestNetworkAgentWrapper mMockNetworkAgent;
|
private TestNetworkAgentWrapper mMockNetworkAgent;
|
||||||
|
|
||||||
|
private VpnInfo mVpnInfo;
|
||||||
|
|
||||||
public MockVpn(int userId) {
|
public MockVpn(int userId) {
|
||||||
super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
|
super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
|
||||||
userId);
|
userId);
|
||||||
@@ -1041,6 +1056,17 @@ public class ConnectivityServiceTest {
|
|||||||
mConnected = false;
|
mConnected = false;
|
||||||
mConfig = null;
|
mConfig = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized VpnInfo getVpnInfo() {
|
||||||
|
if (mVpnInfo != null) return mVpnInfo;
|
||||||
|
|
||||||
|
return super.getVpnInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setVpnInfo(VpnInfo vpnInfo) {
|
||||||
|
mVpnInfo = vpnInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mockVpn(int uid) {
|
private void mockVpn(int uid) {
|
||||||
@@ -6402,7 +6428,7 @@ public class ConnectivityServiceTest {
|
|||||||
new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
|
new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
|
||||||
try {
|
try {
|
||||||
mService.registerConnectivityDiagnosticsCallback(
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
mConnectivityDiagnosticsCallback, request);
|
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
|
||||||
fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
|
fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
|
||||||
} catch (IllegalArgumentException expected) {
|
} catch (IllegalArgumentException expected) {
|
||||||
}
|
}
|
||||||
@@ -6416,7 +6442,7 @@ public class ConnectivityServiceTest {
|
|||||||
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
|
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
|
||||||
|
|
||||||
mService.registerConnectivityDiagnosticsCallback(
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
mConnectivityDiagnosticsCallback, wifiRequest);
|
mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
|
||||||
|
|
||||||
verify(mIBinder, timeout(TIMEOUT_MS))
|
verify(mIBinder, timeout(TIMEOUT_MS))
|
||||||
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
|
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
|
||||||
@@ -6440,7 +6466,7 @@ public class ConnectivityServiceTest {
|
|||||||
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
|
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
|
||||||
|
|
||||||
mService.registerConnectivityDiagnosticsCallback(
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
mConnectivityDiagnosticsCallback, wifiRequest);
|
mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
|
||||||
|
|
||||||
verify(mIBinder, timeout(TIMEOUT_MS))
|
verify(mIBinder, timeout(TIMEOUT_MS))
|
||||||
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
|
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
|
||||||
@@ -6451,7 +6477,7 @@ public class ConnectivityServiceTest {
|
|||||||
|
|
||||||
// Register the same callback again
|
// Register the same callback again
|
||||||
mService.registerConnectivityDiagnosticsCallback(
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
mConnectivityDiagnosticsCallback, wifiRequest);
|
mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
|
||||||
|
|
||||||
// Block until all other events are done processing.
|
// Block until all other events are done processing.
|
||||||
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
|
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
|
||||||
@@ -6460,4 +6486,145 @@ public class ConnectivityServiceTest {
|
|||||||
mService.mConnectivityDiagnosticsCallbacks.containsKey(
|
mService.mConnectivityDiagnosticsCallbacks.containsKey(
|
||||||
mConnectivityDiagnosticsCallback));
|
mConnectivityDiagnosticsCallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
|
||||||
|
final NetworkAgentInfo naiWithoutUid =
|
||||||
|
new NetworkAgentInfo(
|
||||||
|
null, null, null, null, null, new NetworkCapabilities(), null,
|
||||||
|
mServiceContext, null, null, mService, null, null, null, 0);
|
||||||
|
|
||||||
|
mServiceContext.setPermission(
|
||||||
|
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
|
||||||
|
assertTrue(
|
||||||
|
"NetworkStack permission not applied",
|
||||||
|
mService.checkConnectivityDiagnosticsPermissions(
|
||||||
|
Process.myPid(), Process.myUid(), naiWithoutUid,
|
||||||
|
mContext.getOpPackageName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
|
||||||
|
final NetworkAgentInfo naiWithoutUid =
|
||||||
|
new NetworkAgentInfo(
|
||||||
|
null, null, null, null, null, new NetworkCapabilities(), null,
|
||||||
|
mServiceContext, null, null, mService, null, null, null, 0);
|
||||||
|
|
||||||
|
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
|
||||||
|
|
||||||
|
assertFalse(
|
||||||
|
"ACCESS_FINE_LOCATION permission necessary for Connectivity Diagnostics",
|
||||||
|
mService.checkConnectivityDiagnosticsPermissions(
|
||||||
|
Process.myPid(), Process.myUid(), naiWithoutUid,
|
||||||
|
mContext.getOpPackageName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
|
||||||
|
final NetworkAgentInfo naiWithoutUid =
|
||||||
|
new NetworkAgentInfo(
|
||||||
|
null, null, null, null, null, new NetworkCapabilities(), null,
|
||||||
|
mServiceContext, null, null, mService, null, null, null, 0);
|
||||||
|
|
||||||
|
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
|
||||||
|
|
||||||
|
// setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
|
||||||
|
// active
|
||||||
|
final VpnInfo info = new VpnInfo();
|
||||||
|
info.ownerUid = Process.myUid();
|
||||||
|
info.vpnIface = "interface";
|
||||||
|
mMockVpn.setVpnInfo(info);
|
||||||
|
assertTrue(
|
||||||
|
"Active VPN permission not applied",
|
||||||
|
mService.checkConnectivityDiagnosticsPermissions(
|
||||||
|
Process.myPid(), Process.myUid(), naiWithoutUid,
|
||||||
|
mContext.getOpPackageName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
|
||||||
|
final NetworkCapabilities nc = new NetworkCapabilities();
|
||||||
|
nc.setAdministratorUids(Arrays.asList(Process.myUid()));
|
||||||
|
final NetworkAgentInfo naiWithUid =
|
||||||
|
new NetworkAgentInfo(
|
||||||
|
null, null, null, null, null, nc, null, mServiceContext, null, null,
|
||||||
|
mService, null, null, null, 0);
|
||||||
|
|
||||||
|
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
|
||||||
|
|
||||||
|
// Disconnect mock vpn so the uid check on NetworkAgentInfo is tested
|
||||||
|
mMockVpn.disconnect();
|
||||||
|
assertTrue(
|
||||||
|
"NetworkCapabilities administrator uid permission not applied",
|
||||||
|
mService.checkConnectivityDiagnosticsPermissions(
|
||||||
|
Process.myPid(), Process.myUid(), naiWithUid, mContext.getOpPackageName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
|
||||||
|
final NetworkCapabilities nc = new NetworkCapabilities();
|
||||||
|
nc.setOwnerUid(Process.myUid());
|
||||||
|
nc.setAdministratorUids(Arrays.asList(Process.myUid()));
|
||||||
|
final NetworkAgentInfo naiWithUid =
|
||||||
|
new NetworkAgentInfo(
|
||||||
|
null, null, null, null, null, nc, null, mServiceContext, null, null,
|
||||||
|
mService, null, null, null, 0);
|
||||||
|
|
||||||
|
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
|
||||||
|
|
||||||
|
// Use wrong pid and uid
|
||||||
|
assertFalse(
|
||||||
|
"Permissions allowed when they shouldn't be granted",
|
||||||
|
mService.checkConnectivityDiagnosticsPermissions(
|
||||||
|
Process.myPid() + 1, Process.myUid() + 1, naiWithUid,
|
||||||
|
mContext.getOpPackageName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupLocationPermissions(
|
||||||
|
int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
|
||||||
|
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||||
|
applicationInfo.targetSdkVersion = targetSdk;
|
||||||
|
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
|
||||||
|
.thenReturn(applicationInfo);
|
||||||
|
|
||||||
|
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
|
||||||
|
|
||||||
|
when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
|
||||||
|
.thenReturn(AppOpsManager.MODE_ALLOWED);
|
||||||
|
|
||||||
|
mServiceContext.setPermission(perm, PERMISSION_GRANTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectivityDiagnosticsCallbackOnConnectivityReport() throws Exception {
|
||||||
|
final NetworkRequest request = new NetworkRequest.Builder().build();
|
||||||
|
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
|
||||||
|
|
||||||
|
mServiceContext.setPermission(
|
||||||
|
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
|
||||||
|
|
||||||
|
mService.registerConnectivityDiagnosticsCallback(
|
||||||
|
mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
|
||||||
|
|
||||||
|
// Block until all other events are done processing.
|
||||||
|
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
|
||||||
|
|
||||||
|
// Connect the cell agent verify that it notifies TestNetworkCallback that it is available
|
||||||
|
final TestNetworkCallback callback = new TestNetworkCallback();
|
||||||
|
mCm.registerDefaultNetworkCallback(callback);
|
||||||
|
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
||||||
|
callback.assertNoCallback();
|
||||||
|
|
||||||
|
// Wait for onConnectivityReport to fire
|
||||||
|
verify(mConnectivityDiagnosticsCallback, timeout(TIMEOUT_MS))
|
||||||
|
.onConnectivityReport(any(ConnectivityReport.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user