diff options
| author | 2020-01-24 16:38:56 +0000 | |
|---|---|---|
| committer | 2020-01-24 16:38:56 +0000 | |
| commit | 172d2ce4999c6937d45af9d72a3d76af2c81e1db (patch) | |
| tree | c762bb4ae63d89e2a3928d4ea4634956cb950249 | |
| parent | d4f206ce741c4adbc4b7409f614ef0b620438c63 (diff) | |
| parent | 2458be40f4063863c6160b55f5eb02404b91d65c (diff) | |
Merge changes I7065d081,Ic7c3a331,Ia432057b am: 2458be40f4
Change-Id: I1e5d79606f63540f2d9ae3187057e2ba84f4dcb8
7 files changed, 389 insertions, 1 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index e66e9a14d494..734d6f692394 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4716,6 +4716,24 @@ package android.net { method public boolean satisfiedBy(android.net.NetworkSpecifier); } + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int); + method public int describeContents(); + method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR; + } + public class TetheringManager { method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); @@ -4764,6 +4782,7 @@ package android.net { public abstract static class TetheringManager.TetheringEventCallback { ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>); method public void onError(@NonNull String, int); method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>); diff --git a/api/test-current.txt b/api/test-current.txt index 01d7261444a0..f79c8eefe642 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1506,6 +1506,24 @@ package android.net { method public void teardownTestNetwork(@NonNull android.net.Network); } + public final class TetheredClient implements android.os.Parcelable { + ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int); + method public int describeContents(); + method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses(); + method @NonNull public android.net.MacAddress getMacAddress(); + method public int getTetheringType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR; + } + + public static final class TetheredClient.AddressInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.net.LinkAddress getAddress(); + method @Nullable public String getHostname(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR; + } + public class TetheringManager { method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback); method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); @@ -1554,6 +1572,7 @@ package android.net { public abstract static class TetheringManager.TetheringEventCallback { ctor public TetheringManager.TetheringEventCallback(); + method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>); method public void onError(@NonNull String, int); method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps); method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>); diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index b0ef15399435..e0adb34dad6c 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -19,7 +19,15 @@ aidl_interface { local_include_dir: "src", include_dirs: ["frameworks/base/core/java"], // For framework parcelables. srcs: [ - "src/android/net/*.aidl", + // @JavaOnlyStableParcelable aidl declarations must not be listed here, as this would cause + // compilation to fail (b/148001843). + "src/android/net/IIntResultListener.aidl", + "src/android/net/ITetheringConnector.aidl", + "src/android/net/ITetheringEventCallback.aidl", + "src/android/net/TetheringCallbackStartedParcel.aidl", + "src/android/net/TetheringConfigurationParcel.aidl", + "src/android/net/TetheringRequestParcel.aidl", + "src/android/net/TetherStatesParcel.aidl", ], backend: { ndk: { @@ -35,6 +43,7 @@ java_library { name: "framework-tethering", sdk_version: "system_current", srcs: [ + "src/android/net/TetheredClient.java", "src/android/net/TetheringManager.java", "src/android/net/TetheringConstants.java", ":framework-tethering-annotations", @@ -63,6 +72,8 @@ java_library { filegroup { name: "framework-tethering-srcs", srcs: [ + "src/android/net/TetheredClient.aidl", + "src/android/net/TetheredClient.java", "src/android/net/TetheringManager.java", "src/android/net/TetheringConstants.java", "src/android/net/IIntResultListener.aidl", diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl new file mode 100644 index 000000000000..0b279b882367 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.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 permissions and + * limitations under the License. + */ +package android.net; + +@JavaOnlyStableParcelable parcelable TetheredClient;
\ No newline at end of file diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java new file mode 100644 index 000000000000..651468846ca8 --- /dev/null +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java @@ -0,0 +1,212 @@ +/* + * 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 permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +/** + * Information on a tethered downstream client. + * @hide + */ +@SystemApi +@TestApi +public final class TetheredClient implements Parcelable { + @NonNull + private final MacAddress mMacAddress; + @NonNull + private final List<AddressInfo> mAddresses; + // TODO: use an @IntDef here + private final int mTetheringType; + + public TetheredClient(@NonNull MacAddress macAddress, + @NonNull Collection<AddressInfo> addresses, int tetheringType) { + mMacAddress = macAddress; + mAddresses = new ArrayList<>(addresses); + mTetheringType = tetheringType; + } + + private TetheredClient(@NonNull Parcel in) { + this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt()); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mMacAddress, flags); + dest.writeTypedList(mAddresses); + dest.writeInt(mTetheringType); + } + + @NonNull + public MacAddress getMacAddress() { + return mMacAddress; + } + + @NonNull + public List<AddressInfo> getAddresses() { + return new ArrayList<>(mAddresses); + } + + public int getTetheringType() { + return mTetheringType; + } + + /** + * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the + * {@link AddressInfo} of the provided {@link TetheredClient}. + * + * <p>Duplicate addresses are removed. + * @hide + */ + public TetheredClient addAddresses(@NonNull TetheredClient other) { + final HashSet<AddressInfo> newAddresses = new HashSet<>( + mAddresses.size() + other.mAddresses.size()); + newAddresses.addAll(mAddresses); + newAddresses.addAll(other.mAddresses); + return new TetheredClient(mMacAddress, newAddresses, mTetheringType); + } + + @Override + public int hashCode() { + return Objects.hash(mMacAddress, mAddresses, mTetheringType); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof TetheredClient)) return false; + final TetheredClient other = (TetheredClient) obj; + return mMacAddress.equals(other.mMacAddress) + && mAddresses.equals(other.mAddresses) + && mTetheringType == other.mTetheringType; + } + + /** + * Information on an lease assigned to a tethered client. + */ + public static final class AddressInfo implements Parcelable { + @NonNull + private final LinkAddress mAddress; + @Nullable + private final String mHostname; + // TODO: use LinkAddress expiration time once it is supported + private final long mExpirationTime; + + /** @hide */ + public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) { + this(address, hostname, 0); + } + + /** @hide */ + public AddressInfo(@NonNull LinkAddress address, String hostname, long expirationTime) { + this.mAddress = address; + this.mHostname = hostname; + this.mExpirationTime = expirationTime; + } + + private AddressInfo(Parcel in) { + this(in.readParcelable(null), in.readString(), in.readLong()); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeParcelable(mAddress, flags); + dest.writeString(mHostname); + dest.writeLong(mExpirationTime); + } + + @NonNull + public LinkAddress getAddress() { + return mAddress; + } + + @Nullable + public String getHostname() { + return mHostname; + } + + /** @hide TODO: use expiration time in LinkAddress */ + public long getExpirationTime() { + return mExpirationTime; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public int hashCode() { + return Objects.hash(mAddress, mHostname, mExpirationTime); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof AddressInfo)) return false; + final AddressInfo other = (AddressInfo) obj; + // Use .equals() for addresses as all changes, including address expiry changes, + // should be included. + return other.mAddress.equals(mAddress) + && Objects.equals(mHostname, other.mHostname) + && mExpirationTime == other.mExpirationTime; + } + + @NonNull + public static final Creator<AddressInfo> CREATOR = new Creator<AddressInfo>() { + @NonNull + @Override + public AddressInfo createFromParcel(@NonNull Parcel in) { + return new AddressInfo(in); + } + + @NonNull + @Override + public AddressInfo[] newArray(int size) { + return new AddressInfo[size]; + } + }; + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Creator<TetheredClient> CREATOR = new Creator<TetheredClient>() { + @NonNull + @Override + public TetheredClient createFromParcel(@NonNull Parcel in) { + return new TetheredClient(in); + } + + @NonNull + @Override + public TetheredClient[] newArray(int size) { + return new TetheredClient[size]; + } + }; +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 58bc4e7633ce..8dacecc4ff2a 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -31,6 +31,7 @@ import android.util.ArrayMap; import android.util.Log; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -653,6 +654,19 @@ public class TetheringManager { * @param error One of {@code TetheringManager#TETHER_ERROR_*}. */ public void onError(@NonNull String ifName, int error) {} + + /** + * Called when the list of tethered clients changes. + * + * <p>This callback provides best-effort information on connected clients based on state + * known to the system, however the list cannot be completely accurate (and should not be + * used for security purposes). For example, clients behind a bridge and using static IP + * assignments are not visible to the tethering device; or even when using DHCP, such + * clients may still be reported by this callback after disconnection as the system cannot + * determine if they are still connected. + * @param clients The new set of tethered clients; the collection is not ordered. + */ + public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {} } /** diff --git a/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt new file mode 100644 index 000000000000..83c19ec14d56 --- /dev/null +++ b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt @@ -0,0 +1,95 @@ +/* + * 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 permissions and + * limitations under the License. + */ + +package android.net + +import android.net.InetAddresses.parseNumericAddress +import android.net.TetheredClient.AddressInfo +import android.net.TetheringManager.TETHERING_BLUETOOTH +import android.net.TetheringManager.TETHERING_USB +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.assertParcelSane +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +private val TEST_MACADDR = MacAddress.fromBytes(byteArrayOf(12, 23, 34, 45, 56, 67)) +private val TEST_OTHER_MACADDR = MacAddress.fromBytes(byteArrayOf(23, 34, 45, 56, 67, 78)) +private val TEST_ADDR1 = LinkAddress(parseNumericAddress("192.168.113.3"), 24) +private val TEST_ADDR2 = LinkAddress(parseNumericAddress("fe80::1:2:3"), 64) +private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, "test_hostname") +private val TEST_ADDRINFO2 = AddressInfo(TEST_ADDR2, null) + +@RunWith(AndroidJUnit4::class) +@SmallTest +class TetheredClientTest { + @Test + fun testParceling() { + assertParcelSane(makeTestClient(), fieldCount = 3) + } + + @Test + fun testEquals() { + assertEquals(makeTestClient(), makeTestClient()) + + // Different mac address + assertNotEquals(makeTestClient(), TetheredClient( + TEST_OTHER_MACADDR, + listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), + TETHERING_BLUETOOTH)) + + // Different hostname + assertNotEquals(makeTestClient(), TetheredClient( + TEST_MACADDR, + listOf(AddressInfo(TEST_ADDR1, "test_other_hostname"), TEST_ADDRINFO2), + TETHERING_BLUETOOTH)) + + // Null hostname + assertNotEquals(makeTestClient(), TetheredClient( + TEST_MACADDR, + listOf(AddressInfo(TEST_ADDR1, null), TEST_ADDRINFO2), + TETHERING_BLUETOOTH)) + + // Missing address + assertNotEquals(makeTestClient(), TetheredClient( + TEST_MACADDR, + listOf(TEST_ADDRINFO2), + TETHERING_BLUETOOTH)) + + // Different type + assertNotEquals(makeTestClient(), TetheredClient( + TEST_MACADDR, + listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), + TETHERING_BLUETOOTH)) + } + + @Test + fun testAddAddresses() { + val client1 = TetheredClient(TEST_MACADDR, listOf(TEST_ADDRINFO1), TETHERING_USB) + val client2 = TetheredClient(TEST_OTHER_MACADDR, listOf(TEST_ADDRINFO2), TETHERING_USB) + assertEquals(TetheredClient( + TEST_MACADDR, + listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), + TETHERING_USB), client1.addAddresses(client2)) + } + + private fun makeTestClient() = TetheredClient( + TEST_MACADDR, + listOf(TEST_ADDRINFO1, TEST_ADDRINFO2), + TETHERING_BLUETOOTH) +}
\ No newline at end of file |