Merge "no-op: Use helper class to handle pending requests" into main

This commit is contained in:
Quang Luong 2025-03-05 23:57:51 -08:00 • committed by Gerrit Code Review
commit bab398f08c
6 changed files with 369 additions and 85 deletions

View file

@ -0,0 +1,164 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest;
import android.net.TetheringManager.TetheringRequest;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class to keep track of tethering requests.
* The intended usage of this class is
* 1) Add a pending request with {@link #addPendingRequest(TetheringRequest)} before asking the link
* layer to start.
* 2) When the link layer is up, use {@link #getOrCreatePendingRequest(int)} to get a request to
* start IP serving with.
* 3) Remove all pending requests with {@link #removeAllPendingRequests(int)}.
* Note: This class is not thread-safe.
* TODO: Add the pending IIntResultListeners at the same time as the pending requests, and
* call them when we get the tether result.
* TODO: Add support for multiple Bluetooth requests before the PAN service connects instead of
* using a separate mPendingPanRequestListeners.
* TODO: Add support for fuzzy-matched requests.
*/
public class RequestTracker {
private static final String TAG = RequestTracker.class.getSimpleName();
private class PendingRequest {
@NonNull
private final TetheringRequest mTetheringRequest;
private PendingRequest(@NonNull TetheringRequest tetheringRequest) {
mTetheringRequest = tetheringRequest;
}
@NonNull
TetheringRequest getTetheringRequest() {
return mTetheringRequest;
}
}
public enum AddResult {
/**
* Request was successfully added
*/
SUCCESS,
/**
* Failure indicating that the request could not be added due to a request of the same type
* with conflicting parameters already pending. If so, we must stop tethering for the
* pending request before trying to add the result again.
*/
FAILURE_CONFLICTING_PENDING_REQUEST
}
/**
* List of pending requests added by {@link #addPendingRequest(TetheringRequest)}. There can be
* only one per type, since we remove every request of the same type when we add a request.
*/
private final List<PendingRequest> mPendingRequests = new ArrayList<>();
@VisibleForTesting
List<TetheringRequest> getPendingTetheringRequests() {
List<TetheringRequest> requests = new ArrayList<>();
for (PendingRequest pendingRequest : mPendingRequests) {
requests.add(pendingRequest.getTetheringRequest());
}
return requests;
}
/**
* Add a pending request and listener. The request should be added before asking the link layer
* to start, and should be retrieved with {@link #getNextPendingRequest(int)} once the link
* layer comes up. The result of the add operation will be returned as an AddResult code.
*/
public AddResult addPendingRequest(@NonNull final TetheringRequest newRequest) {
// Check the existing requests to see if it is OK to add the new request.
for (PendingRequest request : mPendingRequests) {
TetheringRequest existingRequest = request.getTetheringRequest();
if (existingRequest.getTetheringType() != newRequest.getTetheringType()) {
continue;
}
// Can't add request if there's a request of the same type with different
// parameters.
if (!existingRequest.equalsIgnoreUidPackage(newRequest)) {
return AddResult.FAILURE_CONFLICTING_PENDING_REQUEST;
}
}
// Remove the existing pending request of the same type. We already filter out for
// conflicting parameters above, so these would have been equivalent anyway (except for
// UID).
removeAllPendingRequests(newRequest.getTetheringType());
mPendingRequests.add(new PendingRequest(newRequest));
return AddResult.SUCCESS;
}
/**
* Gets the next pending TetheringRequest of a given type, or creates a placeholder request if
* there are none.
* Note: There are edge cases where the pending request is absent and we must temporarily
* synthesize a placeholder request, such as if stopTethering was called before link
* layer went up, or if the link layer goes up without us poking it (e.g. adb shell
* cmd wifi start-softap). These placeholder requests only specify the tethering type
* and the default connectivity scope.
*/
@NonNull
public TetheringRequest getOrCreatePendingRequest(int type) {
TetheringRequest pending = getNextPendingRequest(type);
if (pending != null) return pending;
Log.w(TAG, "No pending TetheringRequest for type " + type + " found, creating a"
+ " placeholder request");
return createPlaceholderRequest(type);
}
/**
* Same as {@link #getOrCreatePendingRequest(int)} but returns {@code null} if there's no
* pending request found.
*
* @param type Tethering type of the pending request
* @return pending request or {@code null} if there are none.
*/
@Nullable
public TetheringRequest getNextPendingRequest(int type) {
for (PendingRequest pendingRequest : mPendingRequests) {
TetheringRequest tetheringRequest =
pendingRequest.getTetheringRequest();
if (tetheringRequest.getTetheringType() == type) return tetheringRequest;
}
return null;
}
/**
* Removes all pending requests of the given tethering type.
*
* @param type Tethering type
*/
public void removeAllPendingRequests(int type) {
mPendingRequests.removeIf(r -> r.getTetheringRequest().getTetheringType() == type);
}
}

View file

@ -29,7 +29,6 @@ import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
@ -78,6 +77,9 @@ import static com.android.networkstack.tethering.metrics.TetheringStatsLog.CORE_
import static com.android.networkstack.tethering.metrics.TetheringStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_LEGACY_TETHER_WITH_TYPE_WIFI_SUCCESS;
import static com.android.networkstack.tethering.metrics.TetheringStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_TETHER_WITH_PLACEHOLDER_REQUEST;
import static com.android.networkstack.tethering.util.TetheringMessageBase.BASE_MAIN_SM;
import static com.android.networkstack.tethering.util.TetheringUtils.createImplicitLocalOnlyTetheringRequest;
import static com.android.networkstack.tethering.util.TetheringUtils.createLegacyGlobalScopeTetheringRequest;
import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest;
import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
@ -241,11 +243,7 @@ public class Tethering {
private final SharedLog mLog = new SharedLog(TAG);
private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
new RemoteCallbackList<>();
// Currently active tethering requests per tethering type. Only one of each type can be
// requested at a time. After a tethering type is requested, the map keeps tethering parameters
// to be used after the interface comes up asynchronously.
private final SparseArray<TetheringRequest> mPendingTetheringRequests =
new SparseArray<>();
private final RequestTracker mRequestTracker;
private final Context mContext;
private final ArrayMap<String, TetherState> mTetherStates;
@ -308,6 +306,7 @@ public class Tethering {
mLooper = mDeps.makeTetheringLooper();
mNotificationUpdater = mDeps.makeNotificationUpdater(mContext, mLooper);
mTetheringMetrics = mDeps.makeTetheringMetrics(mContext);
mRequestTracker = new RequestTracker();
// This is intended to ensrure that if something calls startTethering(bluetooth) just after
// bluetooth is enabled. Before onServiceConnected is called, store the calls into this
@ -704,13 +703,13 @@ public class Tethering {
final IIntResultListener listener) {
mHandler.post(() -> {
final int type = request.getTetheringType();
final TetheringRequest unfinishedRequest = mPendingTetheringRequests.get(type);
// If tethering is already enabled with a different request,
// disable before re-enabling.
if (unfinishedRequest != null && !unfinishedRequest.equalsIgnoreUidPackage(request)) {
stopTetheringInternal(type);
RequestTracker.AddResult result = mRequestTracker.addPendingRequest(request);
// If tethering is already pending with a conflicting request, stop tethering before
// starting.
if (result == RequestTracker.AddResult.FAILURE_CONFLICTING_PENDING_REQUEST) {
stopTetheringInternal(type); // Also removes the request from the tracker.
mRequestTracker.addPendingRequest(request);
}
mPendingTetheringRequests.put(type, request);
if (request.isExemptFromEntitlementCheck()) {
mEntitlementMgr.setExemptedDownstreamType(type);
@ -730,9 +729,7 @@ public class Tethering {
}
private boolean isTetheringTypePendingOrServing(final int type) {
for (int i = 0; i < mPendingTetheringRequests.size(); i++) {
if (mPendingTetheringRequests.valueAt(i).getTetheringType() == type) return true;
}
if (mRequestTracker.getNextPendingRequest(type) != null) return true;
for (TetherState state : mTetherStates.values()) {
// TODO: isCurrentlyServing only starts returning true once the IpServer has processed
// the CMD_TETHER_REQUESTED. Ensure that we consider the request to be serving even when
@ -763,7 +760,7 @@ public class Tethering {
}
void stopTetheringInternal(int type) {
mPendingTetheringRequests.remove(type);
mRequestTracker.removeAllPendingRequests(type);
// Using a placeholder here is ok since none of the disable APIs use the request for
// anything. We simply need the tethering type to know which link layer to poke for removal.
@ -821,7 +818,7 @@ public class Tethering {
// If changing tethering fail, remove corresponding request
// no matter who trigger the start/stop.
if (result != TETHER_ERROR_NO_ERROR) {
mPendingTetheringRequests.remove(type);
mRequestTracker.removeAllPendingRequests(type);
mTetheringMetrics.updateErrorCode(type, result);
mTetheringMetrics.sendReport(type);
}
@ -990,7 +987,7 @@ public class Tethering {
if (this != mBluetoothCallback) return;
final TetheringRequest request =
getOrCreatePendingTetheringRequest(TETHERING_BLUETOOTH);
mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH);
enableIpServing(request, iface);
mConfiguredBluetoothIface = iface;
}
@ -1047,7 +1044,8 @@ public class Tethering {
return;
}
final TetheringRequest request = getOrCreatePendingTetheringRequest(TETHERING_ETHERNET);
final TetheringRequest request = mRequestTracker.getOrCreatePendingRequest(
TETHERING_ETHERNET);
enableIpServing(request, iface);
mConfiguredEthernetIface = iface;
}
@ -1079,61 +1077,6 @@ public class Tethering {
return TETHER_ERROR_NO_ERROR;
}
/**
* Create a legacy tethering request for calls to the legacy tether() API, which doesn't take an
* explicit request. These are always CONNECTIVITY_SCOPE_GLOBAL, per historical behavior.
*/
private TetheringRequest createLegacyGlobalScopeTetheringRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
return request;
}
/**
* Create a local-only implicit tethering request. This is used for Wifi local-only hotspot and
* Wifi P2P, which start tethering based on the WIFI_(AP/P2P)_STATE_CHANGED broadcasts.
*/
@NonNull
private TetheringRequest createImplicitLocalOnlyTetheringRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_IMPLICIT;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
return request;
}
/**
* Create a placeholder request. This is used in case we try to find a pending request but there
* is none (e.g. stopTethering removed a pending request), or for cases where we only have the
* tethering type (e.g. stopTethering(int)).
*/
@NonNull
private TetheringRequest createPlaceholderRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
return request;
}
/**
* Gets the TetheringRequest that #startTethering was called with but is waiting for the link
* layer event to indicate the interface is available to tether.
* Note: There are edge cases where the pending request is absent and we must temporarily
* synthesize a placeholder request, such as if stopTethering was called before link layer
* went up, or if the link layer goes up without us poking it (e.g. adb shell cmd wifi
* start-softap). These placeholder requests only specify the tethering type and the
* default connectivity scope.
*/
@NonNull
private TetheringRequest getOrCreatePendingTetheringRequest(int type) {
TetheringRequest pending = mPendingTetheringRequests.get(type);
if (pending != null) return pending;
Log.w(TAG, "No pending TetheringRequest for type " + type + " found, creating a placeholder"
+ " request");
return createPlaceholderRequest(type);
}
private void handleLegacyTether(String iface, final IIntResultListener listener) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// After V, the TetheringManager and ConnectivityManager tether and untether methods
@ -1151,7 +1094,7 @@ public class Tethering {
} catch (RemoteException e) { }
}
TetheringRequest request = getPendingTetheringRequest(type);
TetheringRequest request = mRequestTracker.getNextPendingRequest(type);
if (request == null) {
request = createLegacyGlobalScopeTetheringRequest(type);
}
@ -1224,7 +1167,7 @@ public class Tethering {
// processed, this will be a no-op and it will not return an error.
//
// This code cannot race with untether() because they both run on the handler thread.
mPendingTetheringRequests.remove(request.getTetheringType());
mRequestTracker.removeAllPendingRequests(request.getTetheringType());
tetherState.ipServer.enable(request);
if (request.getRequestType() == REQUEST_TYPE_PLACEHOLDER) {
TerribleErrorLog.logTerribleError(TetheringStatsLog::write,
@ -1590,8 +1533,8 @@ public class Tethering {
}
@VisibleForTesting
SparseArray<TetheringRequest> getPendingTetheringRequests() {
return mPendingTetheringRequests;
List<TetheringRequest> getPendingTetheringRequests() {
return mRequestTracker.getPendingTetheringRequests();
}
@VisibleForTesting
@ -1651,10 +1594,6 @@ public class Tethering {
}
}
final TetheringRequest getPendingTetheringRequest(int type) {
return mPendingTetheringRequests.get(type, null);
}
private void enableIpServing(@NonNull TetheringRequest request, String ifname) {
enableIpServing(request, ifname, false /* isNcm */);
}
@ -1742,7 +1681,7 @@ public class Tethering {
switch (wifiIpMode) {
case IFACE_IP_MODE_TETHERED:
type = maybeInferWifiTetheringType(ifname);
request = getOrCreatePendingTetheringRequest(type);
request = mRequestTracker.getOrCreatePendingRequest(type);
// Wifi requests will always have CONNECTIVITY_SCOPE_GLOBAL, because
// TetheringRequest.Builder will not allow callers to set CONNECTIVITY_SCOPE_LOCAL
// for TETHERING_WIFI. However, if maybeInferWifiTetheringType returns a non-Wifi
@ -1797,7 +1736,7 @@ public class Tethering {
return;
}
final TetheringRequest request = getOrCreatePendingTetheringRequest(tetheringType);
final TetheringRequest request = mRequestTracker.getOrCreatePendingRequest(tetheringType);
if (ifaces != null) {
for (String iface : ifaces) {
if (ifaceNameToType(iface) == tetheringType) {

View file

@ -15,7 +15,11 @@
*/
package com.android.networkstack.tethering.util;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import android.net.TetherStatsParcel;
import android.net.TetheringManager.TetheringRequest;
import android.util.Log;
import androidx.annotation.NonNull;
@ -166,4 +170,41 @@ public class TetheringUtils {
return null;
}
}
/**
* Create a legacy tethering request for calls to the legacy tether() API, which doesn't take an
* explicit request. These are always CONNECTIVITY_SCOPE_GLOBAL, per historical behavior.
*/
@NonNull
public static TetheringRequest createLegacyGlobalScopeTetheringRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
return request;
}
/**
* Create a local-only implicit tethering request. This is used for Wifi local-only hotspot and
* Wifi P2P, which start tethering based on the WIFI_(AP/P2P)_STATE_CHANGED broadcasts.
*/
@NonNull
public static TetheringRequest createImplicitLocalOnlyTetheringRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_IMPLICIT;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
return request;
}
/**
* Create a placeholder request. This is used in case we try to find a pending request but there
* is none (e.g. stopTethering removed a pending request), or for cases where we only have the
* tethering type (e.g. stopTethering(int)).
*/
@NonNull
public static TetheringRequest createPlaceholderRequest(int type) {
final TetheringRequest request = new TetheringRequest.Builder(type).build();
request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_PLACEHOLDER;
request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL;
return request;
}
}

View file

@ -57,6 +57,7 @@ java_defaults {
"mockito-target-extended-minus-junit4",
"net-tests-utils",
"testables",
"truth",
],
// TODO(b/147200698) change sdk_version to module-current and
// remove framework-minus-apex, ext, and framework-res

View file

@ -0,0 +1,139 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkstack.tethering;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest;
import static com.google.common.truth.Truth.assertThat;
import android.net.TetheringManager.TetheringRequest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.networkstack.tethering.RequestTracker.AddResult;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RequestTrackerTest {
private RequestTracker mRequestTracker;
@Before
public void setUp() {
mRequestTracker = new RequestTracker();
}
@Test
public void testNoRequestsAdded_noPendingRequests() {
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
}
@Test
public void testAddRequest_successResultAndBecomesNextPending() {
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
final AddResult result = mRequestTracker.addPendingRequest(request);
assertThat(result).isEqualTo(AddResult.SUCCESS);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
}
@Test
public void testAddRequest_equalRequestExists_successResultAndBecomesNextPending() {
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
mRequestTracker.addPendingRequest(request);
final TetheringRequest equalRequest = new TetheringRequest.Builder(TETHERING_WIFI).build();
final AddResult result = mRequestTracker.addPendingRequest(equalRequest);
assertThat(result).isEqualTo(AddResult.SUCCESS);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
}
@Test
public void testAddRequest_equalButDifferentUidRequest_successResultAndBecomesNextPending() {
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
request.setUid(1000);
request.setPackageName("package");
final TetheringRequest differentUid = new TetheringRequest.Builder(TETHERING_WIFI).build();
differentUid.setUid(2000);
differentUid.setPackageName("package2");
mRequestTracker.addPendingRequest(request);
final AddResult result = mRequestTracker.addPendingRequest(differentUid);
assertThat(result).isEqualTo(AddResult.SUCCESS);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(differentUid);
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
.isEqualTo(differentUid);
}
@Test
public void testAddConflictingRequest_returnsFailureConflictingPendingRequest() {
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
.setExemptFromEntitlementCheck(true).build();
mRequestTracker.addPendingRequest(request);
final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest);
assertThat(result).isEqualTo(AddResult.FAILURE_CONFLICTING_PENDING_REQUEST);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
}
@Test
public void testRemoveAllPendingRequests_noPendingRequestsLeft() {
final TetheringRequest firstRequest = new TetheringRequest.Builder(TETHERING_WIFI).build();
firstRequest.setUid(1000);
firstRequest.setPackageName("package");
mRequestTracker.addPendingRequest(firstRequest);
final TetheringRequest secondRequest = new TetheringRequest.Builder(TETHERING_WIFI).build();
secondRequest.setUid(2000);
secondRequest.setPackageName("package2");
mRequestTracker.addPendingRequest(secondRequest);
mRequestTracker.removeAllPendingRequests(TETHERING_WIFI);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
}
@Test
public void testRemoveAllPendingRequests_differentTypeExists_doesNotRemoveDifferentType() {
final TetheringRequest differentType = new TetheringRequest.Builder(TETHERING_USB).build();
mRequestTracker.addPendingRequest(differentType);
mRequestTracker.removeAllPendingRequests(TETHERING_WIFI);
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_USB)).isEqualTo(differentType);
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_USB))
.isEqualTo(differentType);
}
}

View file

@ -964,7 +964,7 @@ public class TetheringTest {
mLooper.dispatchAll();
assertEquals(1, mTethering.getPendingTetheringRequests().size());
assertEquals(request, mTethering.getPendingTetheringRequests().get(TETHERING_USB));
assertTrue(mTethering.getPendingTetheringRequests().get(0).equals(request));
if (mTethering.getTetheringConfiguration().isUsingNcm()) {
verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NCM);