diff options
author | Remi NGUYEN VAN <reminv@google.com> | 2020-12-23 12:45:08 +0900 |
---|---|---|
committer | Remi NGUYEN VAN <reminv@google.com> | 2020-12-25 03:54:19 +0000 |
commit | 92f546d4bd3e7a011a197231deda4ab9c5e7b02c (patch) | |
tree | ad6b4df79967dcd01dfd3b4bab5099cf2dd12044 | |
parent | ba3f1179a8ac84a04212fbb3cbc48669ae3b850a (diff) |
Migrate away from AsyncChannel in NetworkAgent
Use two oneway binder interfaces instead.
The interfaces post messages to handlers as was implemented before, but
provide a more strictly defined interface, with less hops between
NetworkAgent, AsyncChannel, and ConnectivityService.
The actual public interface is the NetworkAgent @SystemApi: the binder
interface is an internal implementation detail.
Test: atest FrameworksNetTests CtsNetTestCasesLatestSdk
Bug: 173574274
Merged-In: Ie364ab50f416e7821e70f4539a881eea828e1256
Change-Id: Ie364ab50f416e7821e70f4539a881eea828e1256
11 files changed, 594 insertions, 206 deletions
diff --git a/Android.bp b/Android.bp index 4b3c22da5c7c..a523f8d7f1f0 100644 --- a/Android.bp +++ b/Android.bp @@ -295,6 +295,7 @@ filegroup { srcs: [ // Java/AIDL sources under frameworks/base ":framework-blobstore-sources", + ":framework-connectivity-sources", // framework-connectivity is not yet a module ":framework-core-sources", ":framework-drm-sources", ":framework-graphics-sources", diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 540ea5c159cc..6cef73dcd089 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -61,6 +61,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.Protocol; @@ -3287,9 +3288,9 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config) { - return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE); + return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE); } /** @@ -3300,10 +3301,10 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) { try { - return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId); + return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 95a2f2efeb7d..cbb11977ef23 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -37,6 +37,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.ResultReceiver; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; @@ -164,7 +165,7 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkAgentConfig config, in int factorySerialNumber); diff --git a/core/java/android/net/NattKeepalivePacketData.aidl b/core/java/android/net/NattKeepalivePacketData.aidl new file mode 100644 index 000000000000..af644b54827c --- /dev/null +++ b/core/java/android/net/NattKeepalivePacketData.aidl @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing perNmissions and + * limitations under the License. + */ +package android.net; + +@JavaOnlyStableParcelable parcelable NattKeepalivePacketData; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 6780167fa63e..4166c2c4f244 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -29,11 +29,12 @@ import android.os.ConditionVariable; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.os.Messenger; +import android.os.RemoteException; import android.util.Log; +import com.android.connectivity.aidl.INetworkAgent; +import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import java.lang.annotation.Retention; @@ -94,12 +95,18 @@ public abstract class NetworkAgent { @Nullable private volatile Network mNetwork; + @Nullable + private volatile INetworkAgentRegistry mRegistry; + + private interface RegistryAction { + void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException; + } + private final Handler mHandler; - private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; private static final boolean VDBG = false; - private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); + private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>(); private volatile long mLastBwRefreshTime = 0; private static final long BW_REFRESH_MIN_WIN_MS = 500; private boolean mBandwidthUpdateScheduled = false; @@ -329,6 +336,17 @@ public abstract class NetworkAgent { */ public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; + /** + * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection. + * obj = INetworkAgentRegistry + */ + private static final int EVENT_AGENT_CONNECTED = BASE + 18; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected. + */ + private static final int EVENT_AGENT_DISCONNECTED = BASE + 19; + private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { // The subtype can be changed with (TODO) setLegacySubtype, but it starts // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description. @@ -402,36 +420,33 @@ public abstract class NetworkAgent { @Override public void handleMessage(Message msg) { switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - if (mAsyncChannel != null) { + case EVENT_AGENT_CONNECTED: { + if (mRegistry != null) { log("Received new connection while already connected!"); } else { if (VDBG) log("NetworkAgent fully connected"); - AsyncChannel ac = new AsyncChannel(); - ac.connected(null, this, msg.replyTo); - ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); synchronized (mPreConnectedQueue) { - mAsyncChannel = ac; - for (Message m : mPreConnectedQueue) { - ac.sendMessage(m); + final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj; + mRegistry = registry; + for (RegistryAction a : mPreConnectedQueue) { + try { + a.execute(registry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Communication error with registry", e); + // Fall through + } } mPreConnectedQueue.clear(); } } break; } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - if (mAsyncChannel != null) mAsyncChannel.disconnect(); - break; - } - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + case EVENT_AGENT_DISCONNECTED: { if (DBG) log("NetworkAgent channel lost"); // let the client know CS is done with us. onNetworkUnwanted(); synchronized (mPreConnectedQueue) { - mAsyncChannel = null; + mRegistry = null; } break; } @@ -494,15 +509,7 @@ public abstract class NetworkAgent { } case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { - ArrayList<Integer> thresholds = - ((Bundle) msg.obj).getIntegerArrayList("thresholds"); - // TODO: Change signal strength thresholds API to use an ArrayList<Integer> - // rather than convert to int[]. - int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; - for (int i = 0; i < intThresholds.length; i++) { - intThresholds[i] = thresholds.get(i); - } - onSignalStrengthThresholdsUpdated(intThresholds); + onSignalStrengthThresholdsUpdated((int[]) msg.obj); break; } case CMD_PREVENT_AUTOMATIC_RECONNECT: { @@ -541,7 +548,7 @@ public abstract class NetworkAgent { } final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context .getSystemService(Context.CONNECTIVITY_SERVICE); - mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), + mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), new NetworkInfo(mInitialConfiguration.info), mInitialConfiguration.properties, mInitialConfiguration.capabilities, mInitialConfiguration.score, mInitialConfiguration.config, providerId); @@ -550,6 +557,95 @@ public abstract class NetworkAgent { return mNetwork; } + private static class NetworkAgentBinder extends INetworkAgent.Stub { + private final Handler mHandler; + + private NetworkAgentBinder(Handler handler) { + mHandler = handler; + } + + @Override + public void onRegistered(@NonNull INetworkAgentRegistry registry) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry)); + } + + @Override + public void onDisconnected() { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED)); + } + + @Override + public void onBandwidthUpdateRequested() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE)); + } + + @Override + public void onValidationStatusChanged( + int validationStatus, @Nullable String captivePortalUrl) { + // TODO: consider using a parcelable as argument when the interface is structured + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl); + mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS, + validationStatus, 0, redirectUrlBundle)); + } + + @Override + public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED, + acceptUnvalidated ? 1 : 0, 0)); + } + + @Override + public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, + slot, intervalDurationMs, packetData)); + } + + @Override + public void onStopSocketKeepalive(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0)); + } + + @Override + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + mHandler.sendMessage(mHandler.obtainMessage( + CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds)); + } + + @Override + public void onPreventAutomaticReconnect() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT)); + } + + @Override + public void onAddNattKeepalivePacketFilter(int slot, + @NonNull NattKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onAddTcpKeepalivePacketFilter(int slot, + @NonNull TcpKeepalivePacketData packetData) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, + slot, 0, packetData)); + } + + @Override + public void onRemoveKeepalivePacketFilter(int slot) { + mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, + slot, 0)); + } + } + /** * Register this network agent with a testing harness. * @@ -559,13 +655,13 @@ public abstract class NetworkAgent { * * @hide */ - public Messenger registerForTest(final Network network) { + public INetworkAgent registerForTest(final Network network) { log("Registering NetworkAgent for test"); synchronized (mRegisterLock) { mNetwork = network; mInitialConfiguration = null; } - return new Messenger(mHandler); + return new NetworkAgentBinder(mHandler); } /** @@ -589,29 +685,17 @@ public abstract class NetworkAgent { return mNetwork; } - private void queueOrSendMessage(int what, Object obj) { - queueOrSendMessage(what, 0, 0, obj); - } - - private void queueOrSendMessage(int what, int arg1, int arg2) { - queueOrSendMessage(what, arg1, arg2, null); - } - - private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { - Message msg = Message.obtain(); - msg.what = what; - msg.arg1 = arg1; - msg.arg2 = arg2; - msg.obj = obj; - queueOrSendMessage(msg); - } - - private void queueOrSendMessage(Message msg) { + private void queueOrSendMessage(@NonNull RegistryAction action) { synchronized (mPreConnectedQueue) { - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(msg); + if (mRegistry != null) { + try { + action.execute(mRegistry); + } catch (RemoteException e) { + Log.wtf(LOG_TAG, "Error executing registry action", e); + // Fall through: the channel is asynchronous and does not report errors back + } } else { - mPreConnectedQueue.add(msg); + mPreConnectedQueue.add(action); } } } @@ -622,7 +706,8 @@ public abstract class NetworkAgent { */ public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { Objects.requireNonNull(linkProperties); - queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); + final LinkProperties lp = new LinkProperties(linkProperties); + queueOrSendMessage(reg -> reg.sendLinkProperties(lp)); } /** @@ -647,9 +732,7 @@ public abstract class NetworkAgent { public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) { final ArrayList<Network> underlyingArray = (underlyingNetworks != null) ? new ArrayList<>(underlyingNetworks) : null; - final Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray); - queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle); + queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray)); } /** @@ -659,7 +742,7 @@ public abstract class NetworkAgent { public void markConnected() { mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, mNetworkInfo.getExtraInfo()); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -672,7 +755,7 @@ public abstract class NetworkAgent { // When unregistering an agent nobody should use the extrainfo (or reason) any more. mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, null /* extraInfo */); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -689,7 +772,7 @@ public abstract class NetworkAgent { @Deprecated public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -711,7 +794,7 @@ public abstract class NetworkAgent { @Deprecated public void setLegacyExtraInfo(@Nullable final String extraInfo) { mNetworkInfo.setExtraInfo(extraInfo); - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); + queueOrSendNetworkInfo(mNetworkInfo); } /** @@ -720,7 +803,11 @@ public abstract class NetworkAgent { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final void sendNetworkInfo(NetworkInfo networkInfo) { - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); + queueOrSendNetworkInfo(new NetworkInfo(networkInfo)); + } + + private void queueOrSendNetworkInfo(NetworkInfo networkInfo) { + queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo)); } /** @@ -731,8 +818,8 @@ public abstract class NetworkAgent { Objects.requireNonNull(networkCapabilities); mBandwidthUpdatePending.set(false); mLastBwRefreshTime = System.currentTimeMillis(); - queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, - new NetworkCapabilities(networkCapabilities)); + final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); + queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc)); } /** @@ -744,7 +831,7 @@ public abstract class NetworkAgent { if (score < 0) { throw new IllegalArgumentException("Score must be >= 0"); } - queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0); + queueOrSendMessage(reg -> reg.sendScore(score)); } /** @@ -784,9 +871,8 @@ public abstract class NetworkAgent { * @hide should move to NetworkAgentConfig. */ public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { - queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, - explicitlySelected ? 1 : 0, - acceptUnvalidated ? 1 : 0); + queueOrSendMessage(reg -> reg.sendExplicitlySelected( + explicitlySelected, acceptUnvalidated)); } /** @@ -909,7 +995,7 @@ public abstract class NetworkAgent { */ public final void sendSocketKeepaliveEvent(int slot, @SocketKeepalive.KeepaliveEvent int event) { - queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event); + queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event)); } /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ public void onSocketKeepaliveEvent(int slot, int reason) { diff --git a/core/java/android/net/TcpKeepalivePacketData.aidl b/core/java/android/net/TcpKeepalivePacketData.aidl new file mode 100644 index 000000000000..fdc7af9fed5c --- /dev/null +++ b/core/java/android/net/TcpKeepalivePacketData.aidl @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing perNmissions and + * limitations under the License. + */ +package android.net; + +@JavaOnlyStableParcelable parcelable TcpKeepalivePacketData; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2e1fbb77cd01..14ef5e6ce85e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -174,6 +174,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.Xml; +import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -2018,7 +2019,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void handleRestrictBackgroundChanged(boolean restrictBackground) { if (mRestrictBackground == restrictBackground) return; - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean curMetered = nai.networkCapabilities.isMetered(); maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, restrictBackground); @@ -2726,7 +2727,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private NetworkAgentInfo[] networksSortedById() { NetworkAgentInfo[] networks = new NetworkAgentInfo[0]; - networks = mNetworkAgentInfos.values().toArray(networks); + networks = mNetworkAgentInfos.toArray(networks); Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId())); return networks; } @@ -2772,11 +2773,6 @@ public class ConnectivityService extends IConnectivityManager.Stub handleAsyncChannelHalfConnect(msg); break; } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai != null) nai.asyncChannel.disconnect(); - break; - } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { handleAsyncChannelDisconnected(msg); break; @@ -2786,8 +2782,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void maybeHandleNetworkAgentMessage(Message msg) { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai == null) { + final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj; + final NetworkAgentInfo nai = arg.first; + if (!mNetworkAgentInfos.contains(nai)) { if (VDBG) { log(String.format("%s from unknown NetworkAgent", eventName(msg.what))); } @@ -2796,7 +2793,7 @@ public class ConnectivityService extends IConnectivityManager.Stub switch (msg.what) { case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { - NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj; + NetworkCapabilities networkCapabilities = (NetworkCapabilities) arg.second; if (networkCapabilities.hasConnectivityManagedCapability()) { Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability."); } @@ -2813,13 +2810,13 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: { - LinkProperties newLp = (LinkProperties) msg.obj; + LinkProperties newLp = (LinkProperties) arg.second; processLinkPropertiesFromAgent(nai, newLp); handleUpdateLinkProperties(nai, newLp); break; } case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: { - NetworkInfo info = (NetworkInfo) msg.obj; + NetworkInfo info = (NetworkInfo) arg.second; updateNetworkInfo(nai, info); break; } @@ -2844,7 +2841,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_SOCKET_KEEPALIVE: { - mKeepaliveTracker.handleEventSocketKeepalive(nai, msg); + mKeepaliveTracker.handleEventSocketKeepalive(nai, msg.arg1, msg.arg2); break; } case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: { @@ -2855,7 +2852,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final ArrayList<Network> underlying; try { - underlying = ((Bundle) msg.obj).getParcelableArrayList( + underlying = ((Bundle) arg.second).getParcelableArrayList( NetworkAgent.UNDERLYING_NETWORKS_KEY); } catch (NullPointerException | ClassCastException e) { break; @@ -2934,8 +2931,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.toShortString()); - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); teardownUnneededNetwork(nai); break; } @@ -3027,13 +3023,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } 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); + nai.onValidationStatusChanged( + valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK, + redirectUrl); // If NetworkMonitor detects partial connectivity before // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification @@ -3067,6 +3060,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } break; } + case NetworkAgentInfo.EVENT_AGENT_REGISTERED: { + handleNetworkAgentRegistered(msg); + break; + } + case NetworkAgentInfo.EVENT_AGENT_DISCONNECTED: { + handleNetworkAgentDisconnected(msg); + break; + } } return true; } @@ -3243,7 +3244,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handlePrivateDnsSettingsChanged() { final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { handlePerNetworkPrivateDnsConfig(nai, cfg); if (networkRequiresPrivateDnsValidation(nai)) { handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); @@ -3341,7 +3342,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleAsyncChannelHalfConnect(Message msg) { ensureRunningOnConnectivityServiceThread(); - final AsyncChannel ac = (AsyncChannel) msg.obj; if (mNetworkProviderInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); @@ -3353,39 +3353,45 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Error connecting NetworkFactory"); mNetworkProviderInfos.remove(msg.obj); } - } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) log("NetworkAgent connected"); - // A network agent has requested a connection. Establish the connection. - mNetworkAgentInfos.get(msg.replyTo).asyncChannel. - sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - } else { - loge("Error connecting NetworkAgent"); - NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); - if (nai != null) { - final boolean wasDefault = isDefaultNetwork(nai); - synchronized (mNetworkForNetId) { - mNetworkForNetId.remove(nai.network.getNetId()); - } - mNetIdManager.releaseNetId(nai.network.getNetId()); - // Just in case. - mLegacyTypeTracker.remove(nai, wasDefault); + } + } + + private void handleNetworkAgentRegistered(Message msg) { + final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj; + if (!mNetworkAgentInfos.contains(nai)) { + return; + } + + if (msg.arg1 == NetworkAgentInfo.ARG_AGENT_SUCCESS) { + if (VDBG) log("NetworkAgent registered"); + } else { + loge("Error connecting NetworkAgent"); + mNetworkAgentInfos.remove(nai); + if (nai != null) { + final boolean wasDefault = isDefaultNetwork(nai); + synchronized (mNetworkForNetId) { + mNetworkForNetId.remove(nai.network.getNetId()); } + mNetIdManager.releaseNetId(nai.network.getNetId()); + // Just in case. + mLegacyTypeTracker.remove(nai, wasDefault); } } } - // This is a no-op if it's called with a message designating a network that has + private void handleNetworkAgentDisconnected(Message msg) { + NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj; + if (mNetworkAgentInfos.contains(nai)) { + disconnectAndDestroyNetwork(nai); + } + } + + // This is a no-op if it's called with a message designating a provider that has // already been destroyed, because its reference will not be found in the relevant // maps. private void handleAsyncChannelDisconnected(Message msg) { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai != null) { - disconnectAndDestroyNetwork(nai); - } else { - NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); - if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); - } + NetworkProviderInfo npi = mNetworkProviderInfos.remove(msg.replyTo); + if (DBG && npi != null) log("unregisterNetworkFactory for " + npi.name); } // Destroys a network, remove references to it from the internal state managed by @@ -3429,7 +3435,7 @@ public class ConnectivityService extends IConnectivityManager.Stub wakeupModifyInterface(iface, nai.networkCapabilities, false); } nai.networkMonitor().notifyNetworkDisconnected(); - mNetworkAgentInfos.remove(nai.messenger); + mNetworkAgentInfos.remove(nai); nai.clatd.update(); synchronized (mNetworkForNetId) { // Remove the NetworkAgent, but don't mark the netId as @@ -3537,7 +3543,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRequests.put(nri.request, nri); mNetworkRequestInfoLogs.log("REGISTER " + nri); if (nri.request.isListen()) { - for (NetworkAgentInfo network : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo network : mNetworkAgentInfos) { if (nri.request.networkCapabilities.hasSignalStrength() && network.satisfiesImmutableCapabilitiesOf(nri.request)) { updateSignalStrengthThresholds(network, "REGISTER", nri.request); @@ -3753,7 +3759,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { // listens don't have a singular affectedNetwork. Check all networks to see // if this listen request applies and remove it. - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { nai.removeRequest(nri.request.requestId); if (nri.request.networkCapabilities.hasSignalStrength() && nai.satisfiesImmutableCapabilitiesOf(nri.request)) { @@ -3826,13 +3832,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (always) { - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept)); + nai.onSaveAcceptUnvalidated(accept); } if (!accept) { // Tell the NetworkAgent to not automatically reconnect to the network. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // Teardown the network. teardownUnneededNetwork(nai); } @@ -3863,13 +3868,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Use the current design or save the user choice into IpMemoryStore. if (always) { - nai.asyncChannel.sendMessage( - NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept)); + nai.onSaveAcceptUnvalidated(accept); } if (!accept) { // Tell the NetworkAgent to not automatically reconnect to the network. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // Tear down the network. teardownUnneededNetwork(nai); } else { @@ -4007,7 +4011,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void rematchForAvoidBadWifiUpdate() { rematchAllNetworksAndRequests(); - for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai: mNetworkAgentInfos) { if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { sendUpdatedScoreToFactories(nai); } @@ -4150,7 +4154,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // to a network that provides no or limited connectivity is not useful, because the user // cannot use that network except through the notification shown by this method, and the // notification is only shown if the network is explicitly selected by the user. - nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + nai.onPreventAutomaticReconnect(); // TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when // NetworkMonitor detects the network is partial connectivity. Need to change the design to @@ -4802,7 +4806,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return new VpnInfo[0]; } List<VpnInfo> infoList = new ArrayList<>(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { VpnInfo info = createVpnInfo(nai); if (info != null) { infoList.add(info); @@ -4903,7 +4907,7 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) { ensureRunningOnConnectivityServiceThread(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) { updateCapabilitiesForNetwork(nai); } @@ -5604,7 +5608,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mAppOpsManager.checkPackage(callerUid, callerPackageName); } - private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { + private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { final SortedSet<Integer> thresholds = new TreeSet<>(); synchronized (nai) { for (final NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -5616,14 +5620,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - return new ArrayList<>(thresholds); + // TODO: use NetworkStackUtils.convertToIntArray after moving it + return ArrayUtils.convertToIntArray(new ArrayList<>(thresholds)); } private void updateSignalStrengthThresholds( NetworkAgentInfo nai, String reason, NetworkRequest request) { - ArrayList<Integer> thresholdsArray = getSignalStrengthThresholds(nai); - Bundle thresholds = new Bundle(); - thresholds.putIntegerArrayList("thresholds", thresholdsArray); + final int[] thresholdsArray = getSignalStrengthThresholds(nai); if (VDBG || (DBG && !"CONNECT".equals(reason))) { String detail; @@ -5633,12 +5636,10 @@ public class ConnectivityService extends IConnectivityManager.Stub detail = reason; } log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s", - detail, Arrays.toString(thresholdsArray.toArray()), nai.toShortString())); + detail, Arrays.toString(thresholdsArray), nai.toShortString())); } - nai.asyncChannel.sendMessage( - android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, - 0, 0, thresholds); + nai.onSignalStrengthThresholdsUpdated(thresholdsArray); } private void ensureValidNetworkSpecifier(NetworkCapabilities nc) { @@ -5748,7 +5749,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai = mNetworkForNetId.get(network.getNetId()); } if (nai != null) { - nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE); + nai.onBandwidthUpdateRequested(); synchronized (mBandwidthRequests) { final int uid = mDeps.getCallingUid(); Integer uidReqs = mBandwidthRequests.get(uid); @@ -5991,7 +5992,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // NetworkAgentInfo keyed off its connecting messenger // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays // NOTE: Only should be accessed on ConnectivityServiceThread, except dump(). - private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = new HashMap<>(); + private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>(); @GuardedBy("mBlockedAppUids") private final HashSet<Integer> mBlockedAppUids = new HashSet<>(); @@ -6039,17 +6040,17 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Register a new agent. {@see #registerNetworkAgent} below. */ - public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig) { - return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, + return registerNetworkAgent(na, networkInfo, linkProperties, networkCapabilities, currentScore, networkAgentConfig, NetworkProvider.ID_NONE); } /** * Register a new agent with ConnectivityService to handle a network. * - * @param messenger a messenger for ConnectivityService to contact the agent asynchronously. + * @param na a reference for ConnectivityService to contact the agent asynchronously. * @param networkInfo the initial info associated with this network. It can be updated later : * see {@link #updateNetworkInfo}. * @param linkProperties the initial link properties of this network. They can be updated @@ -6062,7 +6063,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param providerId the ID of the provider owning this NetworkAgent. * @return the network created for this agent. */ - public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { @@ -6074,14 +6075,14 @@ public class ConnectivityService extends IConnectivityManager.Stub final int uid = mDeps.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - return registerNetworkAgentInternal(messenger, networkInfo, linkProperties, + return registerNetworkAgentInternal(na, networkInfo, linkProperties, networkCapabilities, currentScore, networkAgentConfig, providerId, uid); } finally { Binder.restoreCallingIdentity(token); } } - private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo, + private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) { if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { @@ -6097,7 +6098,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network // satisfies mDefaultRequest. final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); - final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), + final NetworkAgentInfo nai = new NetworkAgentInfo(na, new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this, mNetd, mDnsResolver, mNMS, providerId, uid); @@ -6115,7 +6116,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.network, name, new NetworkMonitorCallbacks(nai)); // NetworkAgentInfo registration will finish when the NetworkMonitor is created. // If the network disconnects or sends any other event before that, messages are deferred by - // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the + // NetworkAgent until nai.connect(), which will be called when finalizing the // registration. return nai.network; } @@ -6123,7 +6124,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { nai.onNetworkMonitorCreated(networkMonitor); if (VDBG) log("Got NetworkAgent Messenger"); - mNetworkAgentInfos.put(nai.messenger, nai); + mNetworkAgentInfos.add(nai); synchronized (mNetworkForNetId) { mNetworkForNetId.put(nai.network.getNetId(), nai); } @@ -6133,7 +6134,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } catch (RemoteException e) { e.rethrowAsRuntimeException(); } - nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger); + nai.notifyRegistered(); NetworkInfo networkInfo = nai.networkInfo; updateNetworkInfo(nai, networkInfo); updateUids(nai, null, nai.networkCapabilities); @@ -6946,7 +6947,7 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } } - nai.asyncChannel.disconnect(); + nai.disconnect(); } private void handleLingerComplete(NetworkAgentInfo oldNetwork) { @@ -7136,7 +7137,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Gather the list of all relevant agents and sort them by score. final ArrayList<NetworkAgentInfo> nais = new ArrayList<>(); - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { if (!nai.everConnected) continue; nais.add(nai); } @@ -7171,7 +7172,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void applyNetworkReassignment(@NonNull final NetworkReassignment changes, final long now) { - final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos.values(); + final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos; // Since most of the time there are only 0 or 1 background networks, it would probably // be more efficient to just use an ArrayList here. TODO : measure performance @@ -7264,7 +7265,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais); // Tear down all unneeded networks. - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (unneeded(nai, UnneededFor.TEARDOWN)) { if (nai.getLingerExpiry() > 0) { // This network has active linger timers and no requests, but is not @@ -7501,7 +7502,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // This has to happen after matching the requests, because callbacks are just requests. notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); } else if (state == NetworkInfo.State.DISCONNECTED) { - networkAgent.asyncChannel.disconnect(); + networkAgent.disconnect(); if (networkAgent.isVPN()) { updateUids(networkAgent, networkAgent.networkCapabilities, null); } @@ -7589,7 +7590,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param newRules The new rules to apply. */ private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) { - for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean metered = nai.networkCapabilities.isMetered(); final boolean oldBlocked, newBlocked; // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid @@ -7695,7 +7696,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureRunningOnConnectivityServiceThread(); ArrayList<Network> defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo nai : mNetworkAgentInfos) { if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) { defaultNetworks.add(nai.network); } @@ -8429,7 +8430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } - for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) { + for (NetworkAgentInfo virtual : mNetworkAgentInfos) { if (virtual.supportsUnderlyingNetworks() && virtual.networkCapabilities.getOwnerUid() == callbackUid && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) { diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 96cbfde2a0a0..34d9ccc15dba 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -18,10 +18,7 @@ package com.android.server.connectivity; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NattSocketKeepalive.NATT_PORT; -import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER; -import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER; import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE; -import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE; import static android.net.SocketKeepalive.BINDER_DIED; import static android.net.SocketKeepalive.DATA_RECEIVED; import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES; @@ -330,10 +327,9 @@ public class KeepaliveTracker { Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.toShortString()); switch (mType) { case TYPE_NATT: - mNai.asyncChannel.sendMessage( - CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); - mNai.asyncChannel - .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); + final NattKeepalivePacketData nattData = (NattKeepalivePacketData) mPacket; + mNai.onAddNattKeepalivePacketFilter(slot, nattData); + mNai.onStartNattSocketKeepalive(slot, mInterval, nattData); break; case TYPE_TCP: try { @@ -342,11 +338,10 @@ public class KeepaliveTracker { handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET); return; } - mNai.asyncChannel.sendMessage( - CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); + final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket; + mNai.onAddTcpKeepalivePacketFilter(slot, tcpData); // TODO: check result from apf and notify of failure as needed. - mNai.asyncChannel - .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); + mNai.onStartTcpSocketKeepalive(slot, mInterval, tcpData); break; default: Log.wtf(TAG, "Starting keepalive with unknown type: " + mType); @@ -394,9 +389,8 @@ public class KeepaliveTracker { mTcpController.stopSocketMonitor(mSlot); // fall through case TYPE_NATT: - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, - mSlot); + mNai.onStopSocketKeepalive(mSlot); + mNai.onRemoveKeepalivePacketFilter(mSlot); break; default: Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); @@ -548,17 +542,13 @@ public class KeepaliveTracker { } /** Handle keepalive events from lower layer. */ - public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, - @NonNull Message message) { - int slot = message.arg1; - int reason = message.arg2; - + public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) { KeepaliveInfo ki = null; try { ki = mKeepalives.get(nai).get(slot); } catch(NullPointerException e) {} if (ki == null) { - Log.e(TAG, "Event " + message.what + "," + slot + "," + reason + Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason + " for unknown keepalive " + slot + " on " + nai.toShortString()); return; } @@ -601,7 +591,7 @@ public class KeepaliveTracker { ki.mStartedState = KeepaliveInfo.NOT_STARTED; cleanupStoppedKeepalive(nai, slot); } else { - Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason + Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason + " for keepalive in wrong state: " + ki.toString()); } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 52b9f5c15c50..841c9706a111 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -27,25 +27,35 @@ import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; import android.net.LinkProperties; +import android.net.NattKeepalivePacketData; import android.net.Network; +import android.net.NetworkAgent; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMonitorManager; import android.net.NetworkRequest; import android.net.NetworkState; +import android.net.TcpKeepalivePacketData; +import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.INetworkManagementService; -import android.os.Messenger; +import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; -import com.android.internal.util.AsyncChannel; +import com.android.connectivity.aidl.INetworkAgent; +import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.util.WakeupMessage; import com.android.server.ConnectivityService; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.SortedSet; import java.util.TreeSet; @@ -221,6 +231,31 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { */ public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001; + /** + * Inform ConnectivityService that the agent is half-connected. + * arg1 = ARG_AGENT_SUCCESS or ARG_AGENT_FAILURE + * obj = NetworkAgentInfo + * @hide + */ + public static final int EVENT_AGENT_REGISTERED = 1002; + + /** + * Inform ConnectivityService that the agent was disconnected. + * obj = NetworkAgentInfo + * @hide + */ + public static final int EVENT_AGENT_DISCONNECTED = 1003; + + /** + * Argument for EVENT_AGENT_HALF_CONNECTED indicating failure. + */ + public static final int ARG_AGENT_FAILURE = 0; + + /** + * Argument for EVENT_AGENT_HALF_CONNECTED indicating success. + */ + public static final int ARG_AGENT_SUCCESS = 1; + // All linger timers for this network, sorted by expiry time. A linger timer is added whenever // a request is moved to a network with a better score, regardless of whether the network is or // was lingering or not. @@ -262,8 +297,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // report is generated. Once non-null, it will never be null again. @Nullable private ConnectivityReport mConnectivityReport; - public final Messenger messenger; - public final AsyncChannel asyncChannel; + public final INetworkAgent networkAgent; + // Only accessed from ConnectivityService handler thread + private final AgentDeathMonitor mDeathMonitor = new AgentDeathMonitor(); public final int factorySerialNumber; @@ -279,13 +315,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { private final Context mContext; private final Handler mHandler; - public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, + public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, int creatorUid) { - this.messenger = messenger; - asyncChannel = ac; + networkAgent = na; network = net; networkInfo = info; linkProperties = lp; @@ -300,6 +335,249 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { this.creatorUid = creatorUid; } + private class AgentDeathMonitor implements IBinder.DeathRecipient { + @Override + public void binderDied() { + notifyDisconnected(); + } + } + + /** + * Notify the NetworkAgent that it was registered, and should be unregistered if it dies. + * + * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be + * registered once. + */ + public void notifyRegistered() { + try { + networkAgent.asBinder().linkToDeath(mDeathMonitor, 0); + networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler)); + } catch (RemoteException e) { + Log.e(TAG, "Error registering NetworkAgent", e); + maybeUnlinkDeathMonitor(); + mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_FAILURE, 0, this) + .sendToTarget(); + return; + } + + mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget(); + } + + /** + * Disconnect the NetworkAgent. Must be called from the ConnectivityService handler thread. + */ + public void disconnect() { + try { + networkAgent.onDisconnected(); + } catch (RemoteException e) { + Log.i(TAG, "Error disconnecting NetworkAgent", e); + // Fall through: it's fine if the remote has died + } + + notifyDisconnected(); + maybeUnlinkDeathMonitor(); + } + + private void maybeUnlinkDeathMonitor() { + try { + networkAgent.asBinder().unlinkToDeath(mDeathMonitor, 0); + } catch (NoSuchElementException e) { + // Was not linked: ignore + } + } + + private void notifyDisconnected() { + // Note this may be called multiple times if ConnectivityService disconnects while the + // NetworkAgent also dies. ConnectivityService ignores disconnects of already disconnected + // agents. + mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED, this).sendToTarget(); + } + + /** + * Notify the NetworkAgent that bandwidth update was requested. + */ + public void onBandwidthUpdateRequested() { + try { + networkAgent.onBandwidthUpdateRequested(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending bandwidth update request event", e); + } + } + + /** + * Notify the NetworkAgent that validation status has changed. + */ + public void onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl) { + try { + networkAgent.onValidationStatusChanged(validationStatus, captivePortalUrl); + } catch (RemoteException e) { + Log.e(TAG, "Error sending validation status change event", e); + } + } + + /** + * Notify the NetworkAgent that the acceptUnvalidated setting should be saved. + */ + public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) { + try { + networkAgent.onSaveAcceptUnvalidated(acceptUnvalidated); + } catch (RemoteException e) { + Log.e(TAG, "Error sending accept unvalidated event", e); + } + } + + /** + * Notify the NetworkAgent that NATT socket keepalive should be started. + */ + public void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + @NonNull NattKeepalivePacketData packetData) { + try { + networkAgent.onStartNattSocketKeepalive(slot, intervalDurationMs, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending NATT socket keepalive start event", e); + } + } + + /** + * Notify the NetworkAgent that TCP socket keepalive should be started. + */ + public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + @NonNull TcpKeepalivePacketData packetData) { + try { + networkAgent.onStartTcpSocketKeepalive(slot, intervalDurationMs, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending TCP socket keepalive start event", e); + } + } + + /** + * Notify the NetworkAgent that socket keepalive should be stopped. + */ + public void onStopSocketKeepalive(int slot) { + try { + networkAgent.onStopSocketKeepalive(slot); + } catch (RemoteException e) { + Log.e(TAG, "Error sending TCP socket keepalive stop event", e); + } + } + + /** + * Notify the NetworkAgent that signal strength thresholds should be updated. + */ + public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { + try { + networkAgent.onSignalStrengthThresholdsUpdated(thresholds); + } catch (RemoteException e) { + Log.e(TAG, "Error sending signal strength thresholds event", e); + } + } + + /** + * Notify the NetworkAgent that automatic reconnect should be prevented. + */ + public void onPreventAutomaticReconnect() { + try { + networkAgent.onPreventAutomaticReconnect(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending prevent automatic reconnect event", e); + } + } + + /** + * Notify the NetworkAgent that a NATT keepalive packet filter should be added. + */ + public void onAddNattKeepalivePacketFilter(int slot, + @NonNull NattKeepalivePacketData packetData) { + try { + networkAgent.onAddNattKeepalivePacketFilter(slot, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending add NATT keepalive packet filter event", e); + } + } + + /** + * Notify the NetworkAgent that a TCP keepalive packet filter should be added. + */ + public void onAddTcpKeepalivePacketFilter(int slot, + @NonNull TcpKeepalivePacketData packetData) { + try { + networkAgent.onAddTcpKeepalivePacketFilter(slot, packetData); + } catch (RemoteException e) { + Log.e(TAG, "Error sending add TCP keepalive packet filter event", e); + } + } + + /** + * Notify the NetworkAgent that a keepalive packet filter should be removed. + */ + public void onRemoveKeepalivePacketFilter(int slot) { + try { + networkAgent.onRemoveKeepalivePacketFilter(slot); + } catch (RemoteException e) { + Log.e(TAG, "Error sending remove keepalive packet filter event", e); + } + } + + // TODO: consider moving out of NetworkAgentInfo into its own class + private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub { + private final Handler mHandler; + + private NetworkAgentMessageHandler(Handler handler) { + mHandler = handler; + } + + @Override + public void sendNetworkCapabilities(NetworkCapabilities nc) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, + new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget(); + } + + @Override + public void sendLinkProperties(LinkProperties lp) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, + new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget(); + } + + @Override + public void sendNetworkInfo(NetworkInfo info) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED, + new Pair<>(NetworkAgentInfo.this, info)).sendToTarget(); + } + + @Override + public void sendScore(int score) { + mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, score, 0, + new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial) { + mHandler.obtainMessage(NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED, + explicitlySelected ? 1 : 0, acceptPartial ? 1 : 0, + new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendSocketKeepaliveEvent(int slot, int reason) { + mHandler.obtainMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE, + slot, reason, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget(); + } + + @Override + public void sendUnderlyingNetworks(@Nullable List<Network> networks) { + final Bundle args = new Bundle(); + if (networks instanceof ArrayList<?>) { + args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, + (ArrayList<Network>) networks); + } else { + args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, + networks == null ? null : new ArrayList<>(networks)); + } + mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED, + new Pair<>(NetworkAgentInfo.this, args)).sendToTarget(); + } + } + /** * Inform NetworkAgentInfo that a new NetworkMonitor was created. */ diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a68044a985be..db7ef19ed089 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -7812,8 +7812,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission( @@ -7828,8 +7827,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7844,8 +7842,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception { final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, null, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7861,8 +7858,7 @@ public class ConnectivityServiceTest { public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception { final Network network = new Network(NET_ID); final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo( - null, null, network, null, null, new NetworkCapabilities(), 0, + new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, @@ -7896,8 +7892,7 @@ public class ConnectivityServiceTest { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setAdministratorUids(new int[] {Process.myUid()}); final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo( - null, null, null, null, null, nc, 0, mServiceContext, null, null, + new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, @@ -7916,8 +7911,7 @@ public class ConnectivityServiceTest { nc.setOwnerUid(Process.myUid()); nc.setAdministratorUids(new int[] {Process.myUid()}); final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo( - null, null, null, null, null, nc, 0, mServiceContext, null, null, + new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index aafa18a532fa..96c56e32f156 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -353,7 +353,7 @@ public class LingerMonitorTest { NetworkCapabilities caps = new NetworkCapabilities(); caps.addCapability(0); caps.addTransportType(transport); - NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, + NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null, caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE, Binder.getCallingUid()); nai.everValidated = true; |