Loading api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -16896,9 +16896,11 @@ package android.net { method public boolean isDefaultNetworkActive(); method public static boolean isNetworkTypeValid(int); method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void releaseNetworkRequest(android.app.PendingIntent); method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public void reportBadNetwork(android.net.Network); method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent); method public deprecated boolean requestRouteToHost(int, int); method public deprecated void setNetworkPreference(int); method public static boolean setProcessDefaultNetwork(android.net.Network); Loading @@ -16911,6 +16913,8 @@ package android.net { field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo"; field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST = "networkRequestNetworkRequest"; field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType"; field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity"; field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; core/java/android/net/ConnectivityManager.java +32 −9 Original line number Diff line number Diff line Loading @@ -2378,17 +2378,15 @@ public class ConnectivityManager { /** * The lookup key for a {@link Network} object included with the intent after * succesfully finding a network for the applications request. Retrieve it with * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. * @hide */ public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; /** * The lookup key for a {@link NetworkRequest} object included with the intent after * succesfully finding a network for the applications request. Retrieve it with * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. * @hide */ public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST = "networkRequestNetworkRequest"; Loading @@ -2397,7 +2395,7 @@ public class ConnectivityManager { /** * Request a network to satisfy a set of {@link NetworkCapabilities}. * * This function behavies identically to the version that takes a NetworkCallback, but instead * This function behaves identically to the version that takes a NetworkCallback, but instead * of {@link NetworkCallback} a {@link PendingIntent} is used. This means * the request may outlive the calling application and get called back when a suitable * network is found. Loading @@ -2418,20 +2416,45 @@ public class ConnectivityManager { * two Intents defined by {@link Intent#filterEquals}), then it will be removed and * replaced by this one, effectively releasing the previous {@link NetworkRequest}. * <p> * The request may be released normally by calling {@link #unregisterNetworkCallback}. * The request may be released normally by calling * {@link #releaseNetworkRequest(android.app.PendingIntent)}. * * @param request {@link NetworkRequest} describing this request. * @param operation Action to perform when the network is available (corresponds * to the {@link NetworkCallback#onAvailable} call. Typically * comes from {@link PendingIntent#getBroadcast}. * @hide * comes from {@link PendingIntent#getBroadcast}. Cannot be null. */ public void requestNetwork(NetworkRequest request, PendingIntent operation) { checkPendingIntent(operation); try { mService.pendingRequestForNetwork(request.networkCapabilities, operation); } catch (RemoteException e) {} } /** * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} * <p> * This method has the same behavior as {@link #unregisterNetworkCallback} with respect to * releasing network resources and disconnecting. * * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the * PendingIntent passed to * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the * corresponding NetworkRequest you'd like to remove. Cannot be null. */ public void releaseNetworkRequest(PendingIntent operation) { checkPendingIntent(operation); try { mService.releasePendingNetworkRequest(operation); } catch (RemoteException e) {} } private void checkPendingIntent(PendingIntent intent) { if (intent == null) { throw new IllegalArgumentException("PendingIntent cannot be null."); } } /** * Registers to receive notifications about all networks which satisfy the given * {@link NetworkRequest}. The callbacks will continue to be called until Loading @@ -2448,7 +2471,7 @@ public class ConnectivityManager { /** * Unregisters callbacks about and possibly releases networks originating from * {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork}, * given {@code NetworkCallback} had previously been used with {@code #requestNetwork}, * any networks that had been connected to only to satisfy that request will be * disconnected. * Loading core/java/android/net/IConnectivityManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,8 @@ interface IConnectivityManager NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); void releasePendingNetworkRequest(in PendingIntent operation); NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, in Messenger messenger, in IBinder binder); Loading services/core/java/com/android/server/ConnectivityService.java +168 −28 Original line number Diff line number Diff line Loading @@ -184,7 +184,8 @@ import javax.net.ssl.SSLSession; /** * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; Loading Loading @@ -382,6 +383,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SYSTEM_READY = 25; /** * used to add a network request with a pending intent * includes a NetworkRequestInfo */ private static final int EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT = 26; /** * used to remove a pending intent and its associated network request. * arg1 = UID of caller * obj = PendingIntent */ private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27; /** Handler used for internal events. */ final private InternalHandler mHandler; Loading @@ -395,6 +409,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private String mNetTransitionWakeLockCausedBy = ""; private int mNetTransitionWakeLockSerialNumber; private int mNetTransitionWakeLockTimeout; private final PowerManager.WakeLock mPendingIntentWakeLock; private InetAddress mDefaultDns; Loading Loading @@ -649,6 +664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; Loading Loading @@ -2131,11 +2147,40 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } // If this method proves to be too slow then we can maintain a separate // pendingIntent => NetworkRequestInfo map. // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo. private NetworkRequestInfo findExistingNetworkRequestInfo(PendingIntent pendingIntent) { Intent intent = pendingIntent.getIntent(); for (Map.Entry<NetworkRequest, NetworkRequestInfo> entry : mNetworkRequests.entrySet()) { PendingIntent existingPendingIntent = entry.getValue().mPendingIntent; if (existingPendingIntent != null && existingPendingIntent.getIntent().filterEquals(intent)) { return entry.getValue(); } } return null; } private void handleRegisterNetworkRequestWithIntent(Message msg) { final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); NetworkRequestInfo existingRequest = findExistingNetworkRequestInfo(nri.mPendingIntent); if (existingRequest != null) { // remove the existing request. if (DBG) log("Replacing " + existingRequest.request + " with " + nri.request + " because their intents matched."); handleReleaseNetworkRequest(existingRequest.request, getCallingUid()); } handleRegisterNetworkRequest(msg); } private void handleRegisterNetworkRequest(Message msg) { final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); final NetworkCapabilities newCap = nri.request.networkCapabilities; int score = 0; mNetworkRequests.put(nri.request, nri); // Check for the best currently alive network that satisfies this request NetworkAgentInfo bestNetwork = null; for (NetworkAgentInfo network : mNetworkAgentInfos.values()) { Loading Loading @@ -2173,7 +2218,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork); } } mNetworkRequests.put(nri.request, nri); if (nri.isRequest) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { Loading @@ -2183,6 +2228,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } private void handleReleaseNetworkRequestWithIntent(PendingIntent pendingIntent, int callingUid) { NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent); if (nri != null) { handleReleaseNetworkRequest(nri.request, callingUid); } } private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { NetworkRequestInfo nri = mNetworkRequests.get(request); if (nri != null) { Loading Loading @@ -2218,11 +2271,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } // Maintain the illusion. When this request arrived, we might have preteneded // Maintain the illusion. When this request arrived, we might have pretended // that a network connected to serve it, even though the network was already // connected. Now that this request has gone away, we might have to pretend // that the network disconnected. LegacyTypeTracker will generate that // phatom disconnect for this type. // phantom disconnect for this type. NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); if (nai != null) { mNetworkForRequestId.remove(nri.request.requestId); Loading Loading @@ -2253,7 +2306,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK: case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: { Loading Loading @@ -2334,6 +2386,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleRegisterNetworkRequest(msg); break; } case EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT: { handleRegisterNetworkRequestWithIntent(msg); break; } case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: { handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1); break; } case EVENT_RELEASE_NETWORK_REQUEST: { handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1); break; Loading Loading @@ -3347,12 +3407,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { static final boolean LISTEN = false; final NetworkRequest request; IBinder mBinder; final PendingIntent mPendingIntent; private final IBinder mBinder; final int mPid; final int mUid; final Messenger messenger; final boolean isRequest; NetworkRequestInfo(NetworkRequest r, PendingIntent pi, boolean isRequest) { request = r; mPendingIntent = pi; messenger = null; mBinder = null; mPid = getCallingPid(); mUid = getCallingUid(); this.isRequest = isRequest; } NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) { super(); messenger = m; Loading @@ -3361,6 +3432,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mPid = getCallingPid(); mUid = getCallingUid(); this.isRequest = isRequest; mPendingIntent = null; try { mBinder.linkToDeath(this, 0); Loading @@ -3370,8 +3442,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void unlinkDeathRecipient() { if (mBinder != null) { mBinder.unlinkToDeath(this, 0); } } public void binderDied() { log("ConnectivityService NetworkRequestInfo binderDied(" + Loading @@ -3381,22 +3455,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { public String toString() { return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + mPid + " for " + request; mPid + " for " + request + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); } } @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, Messenger messenger, int timeoutMs, IBinder binder, int legacyType) { networkCapabilities = new NetworkCapabilities(networkCapabilities); enforceNetworkRequestPermissions(networkCapabilities); enforceMeteredApnPolicy(networkCapabilities); if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); if (timeoutMs > 0) { mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST, nri), timeoutMs); } return networkRequest; } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); } else { enforceChangePermission(); } } networkCapabilities = new NetworkCapabilities(networkCapabilities); private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { // if UID is restricted, don't allow them to bring up metered APNs if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == false) { Loading @@ -3411,29 +3509,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } } if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, PendingIntent operation) { checkNotNull(operation, "PendingIntent cannot be null."); networkCapabilities = new NetworkCapabilities(networkCapabilities); enforceNetworkRequestPermissions(networkCapabilities); enforceMeteredApnPolicy(networkCapabilities); NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, if (DBG) log("pendingRequest for " + networkRequest + " to trigger " + operation); NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation, NetworkRequestInfo.REQUEST); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); if (timeoutMs > 0) { mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST, nri), timeoutMs); } mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri)); return networkRequest; } @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, PendingIntent operation) { // TODO return null; public void releasePendingNetworkRequest(PendingIntent operation) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, getCallingUid(), 0, operation)); } @Override Loading Loading @@ -3727,6 +3826,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType) { if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE) { Intent intent = new Intent(); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST_NETWORK, nri.request); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST_NETWORK_REQUEST, networkAgent.network); sendIntent(nri.mPendingIntent, intent); } // else not handled } private void sendIntent(PendingIntent pendingIntent, Intent intent) { mPendingIntentWakeLock.acquire(); try { if (DBG) log("Sending " + pendingIntent); pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */); } catch (PendingIntent.CanceledException e) { if (DBG) log(pendingIntent + " was not sent, it had been canceled."); mPendingIntentWakeLock.release(); releasePendingNetworkRequest(pendingIntent); } // ...otherwise, mPendingIntentWakeLock.release() gets called by onSendFinished() } @Override public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras) { if (DBG) log("Finished sending " + pendingIntent); mPendingIntentWakeLock.release(); releasePendingNetworkRequest(pendingIntent); } private void callCallbackForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType) { if (nri.messenger == null) return; // Default request has no msgr Loading Loading @@ -4137,7 +4269,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // } else if (nai.networkMonitor.isEvaluating()) { // notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType); // } if (nri.mPendingIntent == null) { callCallbackForRequest(nri, nai, notifyType); } else { sendPendingIntentForRequest(nri, nai, notifyType); } } private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) { Loading Loading @@ -4196,7 +4332,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkRequest nr = networkAgent.networkRequests.valueAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); if (VDBG) log(" sending notification for " + nr); if (nri.mPendingIntent == null) { callCallbackForRequest(nri, networkAgent, notifyType); } else { sendPendingIntentForRequest(nri, networkAgent, notifyType); } } } Loading Loading
api/current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -16896,9 +16896,11 @@ package android.net { method public boolean isDefaultNetworkActive(); method public static boolean isNetworkTypeValid(int); method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void releaseNetworkRequest(android.app.PendingIntent); method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public void reportBadNetwork(android.net.Network); method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent); method public deprecated boolean requestRouteToHost(int, int); method public deprecated void setNetworkPreference(int); method public static boolean setProcessDefaultNetwork(android.net.Network); Loading @@ -16911,6 +16913,8 @@ package android.net { field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo"; field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST = "networkRequestNetworkRequest"; field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType"; field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity"; field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
core/java/android/net/ConnectivityManager.java +32 −9 Original line number Diff line number Diff line Loading @@ -2378,17 +2378,15 @@ public class ConnectivityManager { /** * The lookup key for a {@link Network} object included with the intent after * succesfully finding a network for the applications request. Retrieve it with * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. * @hide */ public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; /** * The lookup key for a {@link NetworkRequest} object included with the intent after * succesfully finding a network for the applications request. Retrieve it with * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. * @hide */ public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST = "networkRequestNetworkRequest"; Loading @@ -2397,7 +2395,7 @@ public class ConnectivityManager { /** * Request a network to satisfy a set of {@link NetworkCapabilities}. * * This function behavies identically to the version that takes a NetworkCallback, but instead * This function behaves identically to the version that takes a NetworkCallback, but instead * of {@link NetworkCallback} a {@link PendingIntent} is used. This means * the request may outlive the calling application and get called back when a suitable * network is found. Loading @@ -2418,20 +2416,45 @@ public class ConnectivityManager { * two Intents defined by {@link Intent#filterEquals}), then it will be removed and * replaced by this one, effectively releasing the previous {@link NetworkRequest}. * <p> * The request may be released normally by calling {@link #unregisterNetworkCallback}. * The request may be released normally by calling * {@link #releaseNetworkRequest(android.app.PendingIntent)}. * * @param request {@link NetworkRequest} describing this request. * @param operation Action to perform when the network is available (corresponds * to the {@link NetworkCallback#onAvailable} call. Typically * comes from {@link PendingIntent#getBroadcast}. * @hide * comes from {@link PendingIntent#getBroadcast}. Cannot be null. */ public void requestNetwork(NetworkRequest request, PendingIntent operation) { checkPendingIntent(operation); try { mService.pendingRequestForNetwork(request.networkCapabilities, operation); } catch (RemoteException e) {} } /** * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} * <p> * This method has the same behavior as {@link #unregisterNetworkCallback} with respect to * releasing network resources and disconnecting. * * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the * PendingIntent passed to * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the * corresponding NetworkRequest you'd like to remove. Cannot be null. */ public void releaseNetworkRequest(PendingIntent operation) { checkPendingIntent(operation); try { mService.releasePendingNetworkRequest(operation); } catch (RemoteException e) {} } private void checkPendingIntent(PendingIntent intent) { if (intent == null) { throw new IllegalArgumentException("PendingIntent cannot be null."); } } /** * Registers to receive notifications about all networks which satisfy the given * {@link NetworkRequest}. The callbacks will continue to be called until Loading @@ -2448,7 +2471,7 @@ public class ConnectivityManager { /** * Unregisters callbacks about and possibly releases networks originating from * {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork}, * given {@code NetworkCallback} had previously been used with {@code #requestNetwork}, * any networks that had been connected to only to satisfy that request will be * disconnected. * Loading
core/java/android/net/IConnectivityManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,8 @@ interface IConnectivityManager NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); void releasePendingNetworkRequest(in PendingIntent operation); NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, in Messenger messenger, in IBinder binder); Loading
services/core/java/com/android/server/ConnectivityService.java +168 −28 Original line number Diff line number Diff line Loading @@ -184,7 +184,8 @@ import javax.net.ssl.SSLSession; /** * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; Loading Loading @@ -382,6 +383,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SYSTEM_READY = 25; /** * used to add a network request with a pending intent * includes a NetworkRequestInfo */ private static final int EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT = 26; /** * used to remove a pending intent and its associated network request. * arg1 = UID of caller * obj = PendingIntent */ private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27; /** Handler used for internal events. */ final private InternalHandler mHandler; Loading @@ -395,6 +409,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private String mNetTransitionWakeLockCausedBy = ""; private int mNetTransitionWakeLockSerialNumber; private int mNetTransitionWakeLockTimeout; private final PowerManager.WakeLock mPendingIntentWakeLock; private InetAddress mDefaultDns; Loading Loading @@ -649,6 +664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; Loading Loading @@ -2131,11 +2147,40 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } // If this method proves to be too slow then we can maintain a separate // pendingIntent => NetworkRequestInfo map. // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo. private NetworkRequestInfo findExistingNetworkRequestInfo(PendingIntent pendingIntent) { Intent intent = pendingIntent.getIntent(); for (Map.Entry<NetworkRequest, NetworkRequestInfo> entry : mNetworkRequests.entrySet()) { PendingIntent existingPendingIntent = entry.getValue().mPendingIntent; if (existingPendingIntent != null && existingPendingIntent.getIntent().filterEquals(intent)) { return entry.getValue(); } } return null; } private void handleRegisterNetworkRequestWithIntent(Message msg) { final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); NetworkRequestInfo existingRequest = findExistingNetworkRequestInfo(nri.mPendingIntent); if (existingRequest != null) { // remove the existing request. if (DBG) log("Replacing " + existingRequest.request + " with " + nri.request + " because their intents matched."); handleReleaseNetworkRequest(existingRequest.request, getCallingUid()); } handleRegisterNetworkRequest(msg); } private void handleRegisterNetworkRequest(Message msg) { final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); final NetworkCapabilities newCap = nri.request.networkCapabilities; int score = 0; mNetworkRequests.put(nri.request, nri); // Check for the best currently alive network that satisfies this request NetworkAgentInfo bestNetwork = null; for (NetworkAgentInfo network : mNetworkAgentInfos.values()) { Loading Loading @@ -2173,7 +2218,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLegacyTypeTracker.add(nri.request.legacyType, bestNetwork); } } mNetworkRequests.put(nri.request, nri); if (nri.isRequest) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { Loading @@ -2183,6 +2228,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } private void handleReleaseNetworkRequestWithIntent(PendingIntent pendingIntent, int callingUid) { NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent); if (nri != null) { handleReleaseNetworkRequest(nri.request, callingUid); } } private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { NetworkRequestInfo nri = mNetworkRequests.get(request); if (nri != null) { Loading Loading @@ -2218,11 +2271,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } // Maintain the illusion. When this request arrived, we might have preteneded // Maintain the illusion. When this request arrived, we might have pretended // that a network connected to serve it, even though the network was already // connected. Now that this request has gone away, we might have to pretend // that the network disconnected. LegacyTypeTracker will generate that // phatom disconnect for this type. // phantom disconnect for this type. NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); if (nai != null) { mNetworkForRequestId.remove(nri.request.requestId); Loading Loading @@ -2253,7 +2306,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK: case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: { Loading Loading @@ -2334,6 +2386,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleRegisterNetworkRequest(msg); break; } case EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT: { handleRegisterNetworkRequestWithIntent(msg); break; } case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: { handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1); break; } case EVENT_RELEASE_NETWORK_REQUEST: { handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1); break; Loading Loading @@ -3347,12 +3407,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { static final boolean LISTEN = false; final NetworkRequest request; IBinder mBinder; final PendingIntent mPendingIntent; private final IBinder mBinder; final int mPid; final int mUid; final Messenger messenger; final boolean isRequest; NetworkRequestInfo(NetworkRequest r, PendingIntent pi, boolean isRequest) { request = r; mPendingIntent = pi; messenger = null; mBinder = null; mPid = getCallingPid(); mUid = getCallingUid(); this.isRequest = isRequest; } NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) { super(); messenger = m; Loading @@ -3361,6 +3432,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mPid = getCallingPid(); mUid = getCallingUid(); this.isRequest = isRequest; mPendingIntent = null; try { mBinder.linkToDeath(this, 0); Loading @@ -3370,8 +3442,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void unlinkDeathRecipient() { if (mBinder != null) { mBinder.unlinkToDeath(this, 0); } } public void binderDied() { log("ConnectivityService NetworkRequestInfo binderDied(" + Loading @@ -3381,22 +3455,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { public String toString() { return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + mPid + " for " + request; mPid + " for " + request + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); } } @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, Messenger messenger, int timeoutMs, IBinder binder, int legacyType) { networkCapabilities = new NetworkCapabilities(networkCapabilities); enforceNetworkRequestPermissions(networkCapabilities); enforceMeteredApnPolicy(networkCapabilities); if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); if (timeoutMs > 0) { mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST, nri), timeoutMs); } return networkRequest; } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); } else { enforceChangePermission(); } } networkCapabilities = new NetworkCapabilities(networkCapabilities); private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) { // if UID is restricted, don't allow them to bring up metered APNs if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) == false) { Loading @@ -3411,29 +3509,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); } } if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, PendingIntent operation) { checkNotNull(operation, "PendingIntent cannot be null."); networkCapabilities = new NetworkCapabilities(networkCapabilities); enforceNetworkRequestPermissions(networkCapabilities); enforceMeteredApnPolicy(networkCapabilities); NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, if (DBG) log("pendingRequest for " + networkRequest + " to trigger " + operation); NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation, NetworkRequestInfo.REQUEST); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); if (timeoutMs > 0) { mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST, nri), timeoutMs); } mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri)); return networkRequest; } @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, PendingIntent operation) { // TODO return null; public void releasePendingNetworkRequest(PendingIntent operation) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, getCallingUid(), 0, operation)); } @Override Loading Loading @@ -3727,6 +3826,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType) { if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE) { Intent intent = new Intent(); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST_NETWORK, nri.request); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST_NETWORK_REQUEST, networkAgent.network); sendIntent(nri.mPendingIntent, intent); } // else not handled } private void sendIntent(PendingIntent pendingIntent, Intent intent) { mPendingIntentWakeLock.acquire(); try { if (DBG) log("Sending " + pendingIntent); pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */); } catch (PendingIntent.CanceledException e) { if (DBG) log(pendingIntent + " was not sent, it had been canceled."); mPendingIntentWakeLock.release(); releasePendingNetworkRequest(pendingIntent); } // ...otherwise, mPendingIntentWakeLock.release() gets called by onSendFinished() } @Override public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras) { if (DBG) log("Finished sending " + pendingIntent); mPendingIntentWakeLock.release(); releasePendingNetworkRequest(pendingIntent); } private void callCallbackForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType) { if (nri.messenger == null) return; // Default request has no msgr Loading Loading @@ -4137,7 +4269,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // } else if (nai.networkMonitor.isEvaluating()) { // notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType); // } if (nri.mPendingIntent == null) { callCallbackForRequest(nri, nai, notifyType); } else { sendPendingIntentForRequest(nri, nai, notifyType); } } private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) { Loading Loading @@ -4196,7 +4332,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkRequest nr = networkAgent.networkRequests.valueAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); if (VDBG) log(" sending notification for " + nr); if (nri.mPendingIntent == null) { callCallbackForRequest(nri, networkAgent, notifyType); } else { sendPendingIntentForRequest(nri, networkAgent, notifyType); } } } Loading