Add the tethering type to TetheringEventCallback methods

Before this change, tethering always report a list of tethered
interfaces and the caller need to use each tethering type's interface
regex to matching tethered list to manual implement the mapping of
tethering type and interface. This change allow caller to get rid of
tethering interface regex.

Bug: 162920185
Bug: 152203943
Test: atest CtsTetheringTest on S

Merged-In: I91bcccd676d109c1b974497ac29bd366a41b8899
Change-Id: I91bcccd676d109c1b974497ac29bd366a41b8899
This commit is contained in:
markchien
2021-05-17 20:43:41 +08:00
committed by Chiachang Wang
parent 43740568b6
commit 35ad54b25e
9 changed files with 331 additions and 72 deletions

View File

@@ -16,15 +16,17 @@
package android.net;
import android.net.TetheringInterface;
/**
* Status details for tethering downstream interfaces.
* {@hide}
*/
parcelable TetherStatesParcel {
String[] availableList;
String[] tetheredList;
String[] localOnlyList;
String[] erroredIfaceList;
TetheringInterface[] availableList;
TetheringInterface[] tetheredList;
TetheringInterface[] localOnlyList;
TetheringInterface[] erroredIfaceList;
// List of Last error code corresponding to each errored iface in erroredIfaceList. */
// TODO: Improve this as b/143122247.
int[] lastErrorList;

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2021 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 android.net;
@JavaOnlyStableParcelable parcelable TetheringInterface;

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2021 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 android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.TetheringManager.TetheringType;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* The mapping of tethering interface and type.
* @hide
*/
@SystemApi
public final class TetheringInterface implements Parcelable {
private final int mType;
private final String mInterface;
public TetheringInterface(@TetheringType int type, @NonNull String iface) {
Objects.requireNonNull(iface);
mType = type;
mInterface = iface;
}
private TetheringInterface(@NonNull Parcel in) {
this(in.readInt(), in.readString());
}
/** Get tethering type. */
public int getType() {
return mType;
}
/** Get tethering interface. */
@NonNull
public String getInterface() {
return mInterface;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeString(mInterface);
}
@Override
public int hashCode() {
return Objects.hash(mType, mInterface);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof TetheringInterface)) return false;
final TetheringInterface other = (TetheringInterface) obj;
return mType == other.mType && mInterface.equals(other.mInterface);
}
@Override
public int describeContents() {
return 0;
}
@NonNull
public static final Creator<TetheringInterface> CREATOR = new Creator<TetheringInterface>() {
@NonNull
@Override
public TetheringInterface createFromParcel(@NonNull Parcel in) {
return new TetheringInterface(in);
}
@NonNull
@Override
public TetheringInterface[] newArray(int size) {
return new TetheringInterface[size];
}
};
@NonNull
@Override
public String toString() {
return "TetheringInterface {mType=" + mType
+ ", mInterface=" + mInterface + "}";
}
}

View File

@@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -43,6 +44,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
@@ -83,7 +85,10 @@ public class TetheringManager {
* {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
* the current state of tethering. Each include a list of
* interface names in that state (may be empty).
*
* @deprecated New client should use TetheringEventCallback instead.
*/
@Deprecated
public static final String ACTION_TETHER_STATE_CHANGED =
"android.net.conn.TETHER_STATE_CHANGED";
@@ -531,7 +536,7 @@ public class TetheringManager {
/**
* Attempt to both alter the mode of USB and Tethering of USB.
*
* @deprecated New client should not use this API anymore. All clients should use
* @deprecated New clients should not use this API anymore. All clients should use
* #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
* not have any upstream.
@@ -978,8 +983,13 @@ public class TetheringManager {
* multiple times later upon changes.
* @param reg The new regular expressions.
*
* @deprecated New clients should use the callbacks with {@link TetheringInterface} which
* has the mapping between tethering type and interface. InterfaceRegex is no longer needed
* to determine the mapping of tethering type and interface.
*
* @hide
*/
@Deprecated
@SystemApi(client = MODULE_LIBRARIES)
default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
@@ -993,15 +1003,43 @@ public class TetheringManager {
*/
default void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
/**
* Called when there was a change in the list of tetherable interfaces. Tetherable
* interface means this interface is available and can be used for tethering.
*
* <p>This will be called immediately after the callback is registered, and may be called
* multiple times later upon changes.
* @param interfaces The set of TetheringInterface of currently tetherable interface.
*/
default void onTetherableInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
// By default, the new callback calls the old callback, so apps
// implementing the old callback just work.
onTetherableInterfacesChanged(toIfaces(interfaces));
}
/**
* Called when there was a change in the list of tethered interfaces.
*
* <p>This will be called immediately after the callback is registered, and may be called
* multiple times later upon changes.
* @param interfaces The list of 0 or more String of currently tethered interface names.
* @param interfaces The lit of 0 or more String of currently tethered interface names.
*/
default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
/**
* Called when there was a change in the list of tethered interfaces.
*
* <p>This will be called immediately after the callback is registered, and may be called
* multiple times later upon changes.
* @param interfaces The set of 0 or more TetheringInterface of currently tethered
* interface.
*/
default void onTetheredInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
// By default, the new callback calls the old callback, so apps
// implementing the old callback just work.
onTetheredInterfacesChanged(toIfaces(interfaces));
}
/**
* Called when there was a change in the list of local-only interfaces.
*
@@ -1011,6 +1049,20 @@ public class TetheringManager {
*/
default void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) {}
/**
* Called when there was a change in the list of local-only interfaces.
*
* <p>This will be called immediately after the callback is registered, and may be called
* multiple times later upon changes.
* @param interfaces The set of 0 or more TetheringInterface of active local-only
* interface.
*/
default void onLocalOnlyInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
// By default, the new callback calls the old callback, so apps
// implementing the old callback just work.
onLocalOnlyInterfacesChanged(toIfaces(interfaces));
}
/**
* Called when an error occurred configuring tethering.
*
@@ -1021,6 +1073,20 @@ public class TetheringManager {
*/
default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
/**
* Called when an error occurred configuring tethering.
*
* <p>This will be called immediately after the callback is registered if the latest status
* on the interface is an error, and may be called multiple times later upon changes.
* @param iface The interface that experienced the error.
* @param error One of {@code TetheringManager#TETHER_ERROR_*}.
*/
default void onError(@NonNull TetheringInterface iface, @TetheringIfaceError int error) {
// By default, the new callback calls the old callback, so apps
// implementing the old callback just work.
onError(iface.getInterface(), error);
}
/**
* Called when the list of tethered clients changes.
*
@@ -1044,9 +1110,37 @@ public class TetheringManager {
}
/**
* Regular expressions used to identify tethering interfaces.
* Covert DownStreamInterface collection to interface String array list. Internal use only.
*
* @hide
*/
public static ArrayList<String> toIfaces(Collection<TetheringInterface> tetherIfaces) {
final ArrayList<String> ifaces = new ArrayList<>();
for (TetheringInterface tether : tetherIfaces) {
ifaces.add(tether.getInterface());
}
return ifaces;
}
private static String[] toIfaces(TetheringInterface[] tetherIfaces) {
final String[] ifaces = new String[tetherIfaces.length];
for (int i = 0; i < tetherIfaces.length; i++) {
ifaces[i] = tetherIfaces[i].getInterface();
}
return ifaces;
}
/**
* Regular expressions used to identify tethering interfaces.
*
* @deprecated Instead of using regex to determine tethering type. New client could use the
* callbacks with {@link TetheringInterface} which has the mapping of type and interface.
* @hide
*/
@Deprecated
@SystemApi(client = MODULE_LIBRARIES)
public static class TetheringInterfaceRegexps {
private final String[] mTetherableBluetoothRegexs;
@@ -1114,10 +1208,10 @@ public class TetheringManager {
}
final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
// Only accessed with a lock on this object
private final HashMap<String, Integer> mErrorStates = new HashMap<>();
private String[] mLastTetherableInterfaces = null;
private String[] mLastTetheredInterfaces = null;
private String[] mLastLocalOnlyInterfaces = null;
private final HashMap<TetheringInterface, Integer> mErrorStates = new HashMap<>();
private TetheringInterface[] mLastTetherableInterfaces = null;
private TetheringInterface[] mLastTetheredInterfaces = null;
private TetheringInterface[] mLastLocalOnlyInterfaces = null;
@Override
public void onUpstreamChanged(Network network) throws RemoteException {
@@ -1128,14 +1222,14 @@ public class TetheringManager {
private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
final String iface = newStates.erroredIfaceList[i];
final Integer lastError = mErrorStates.get(iface);
final TetheringInterface tetherIface = newStates.erroredIfaceList[i];
final Integer lastError = mErrorStates.get(tetherIface);
final int newError = newStates.lastErrorList[i];
if (newError != TETHER_ERROR_NO_ERROR
&& !Objects.equals(lastError, newError)) {
callback.onError(iface, newError);
callback.onError(tetherIface, newError);
}
mErrorStates.put(iface, newError);
mErrorStates.put(tetherIface, newError);
}
}
@@ -1144,7 +1238,7 @@ public class TetheringManager {
if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
mLastTetherableInterfaces = newStates.availableList.clone();
callback.onTetherableInterfacesChanged(
Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
Collections.unmodifiableSet((new ArraySet(mLastTetherableInterfaces))));
}
private synchronized void maybeSendTetheredIfacesChangedCallback(
@@ -1152,7 +1246,7 @@ public class TetheringManager {
if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
mLastTetheredInterfaces = newStates.tetheredList.clone();
callback.onTetheredInterfacesChanged(
Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
Collections.unmodifiableSet((new ArraySet(mLastTetheredInterfaces))));
}
private synchronized void maybeSendLocalOnlyIfacesChangedCallback(
@@ -1160,7 +1254,7 @@ public class TetheringManager {
if (Arrays.equals(mLastLocalOnlyInterfaces, newStates.localOnlyList)) return;
mLastLocalOnlyInterfaces = newStates.localOnlyList.clone();
callback.onLocalOnlyInterfacesChanged(
Collections.unmodifiableList(Arrays.asList(mLastLocalOnlyInterfaces)));
Collections.unmodifiableSet((new ArraySet(mLastLocalOnlyInterfaces))));
}
// Called immediately after the callbacks are registered.
@@ -1262,8 +1356,8 @@ public class TetheringManager {
if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
int i = 0;
for (String errored : mTetherStatesParcel.erroredIfaceList) {
if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
for (TetheringInterface errored : mTetherStatesParcel.erroredIfaceList) {
if (iface.equals(errored.getInterface())) return mTetherStatesParcel.lastErrorList[i];
i++;
}
@@ -1327,7 +1421,7 @@ public class TetheringManager {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
return mTetherStatesParcel.availableList;
return toIfaces(mTetherStatesParcel.availableList);
}
/**
@@ -1341,7 +1435,7 @@ public class TetheringManager {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
return mTetherStatesParcel.tetheredList;
return toIfaces(mTetherStatesParcel.tetheredList);
}
/**
@@ -1361,7 +1455,7 @@ public class TetheringManager {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
return mTetherStatesParcel.erroredIfaceList;
return toIfaces(mTetherStatesParcel.erroredIfaceList);
}
/**