diff options
62 files changed, 1670 insertions, 575 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index d3e1e8c4c2bc..9747647845ed 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1440,6 +1440,7 @@ package android.net { } public class ConnectivityManager { + method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; diff --git a/config/OWNERS b/config/OWNERS index 53f80e698d83..3d4924df3462 100644 --- a/config/OWNERS +++ b/config/OWNERS @@ -1,5 +1,5 @@ # compat-team@ for changes to hiddenapi files -per-file hiddenapi-* = andreionea@google.com, atrost@google.com, mathewi@google.com, satayev@google.com +per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com # Escalations: -per-file hiddenapi-* = bdc@google.com, narayan@google.com
\ No newline at end of file +per-file hiddenapi-* = bdc@google.com, narayan@google.com diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS index 8aceb565315c..e1ef54460b56 100644 --- a/core/java/android/annotation/OWNERS +++ b/core/java/android/annotation/OWNERS @@ -1,3 +1,3 @@ tnorbye@google.com aurimas@google.com -per-file UnsupportedAppUsage.java = mathewi@google.com, dbrazdil@google.com, atrost@google.com, andreionea@google.com +per-file UnsupportedAppUsage.java = mathewi@google.com, satayev@google.com, andreionea@google.com diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ad07e7cf4d5f..6b713602215a 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -48,6 +48,7 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; @@ -4735,4 +4736,28 @@ public class ConnectivityManager { Log.d(TAG, "StackLog:" + sb.toString()); } } + + /** + * Simulates a Data Stall for the specified Network. + * + * <p>The caller must be the owner of the specified Network. + * + * @param detectionMethod The detection method used to identify the Data Stall. + * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds. + * @param network The Network for which a Data Stall is being simluated. + * @param extras The PersistableBundle of extras included in the Data Stall notification. + * @throws SecurityException if the caller is not the owner of the given network. + * @hide + */ + @TestApi + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS, + android.Manifest.permission.NETWORK_STACK}) + public void simulateDataStall(int detectionMethod, long timestampMillis, + @NonNull Network network, @NonNull PersistableBundle extras) { + try { + mService.simulateDataStall(detectionMethod, timestampMillis, network, extras); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b0f79bcc0b23..d7f178cd0a9b 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.app.PendingIntent; import android.net.ConnectionInfo; +import android.net.ConnectivityDiagnosticsManager; import android.net.IConnectivityDiagnosticsCallback; import android.net.LinkProperties; import android.net.Network; @@ -33,6 +34,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.os.ResultReceiver; import com.android.internal.net.LegacyVpnInfo; @@ -228,4 +230,7 @@ interface IConnectivityManager void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback); IBinder startOrGetTestNetworkService(); + + void simulateDataStall(int detectionMethod, long timestampMillis, in Network network, + in PersistableBundle extras); } diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 836624beb3b2..407ff04dc4a3 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -101,6 +101,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { private final boolean mIsBypassable; // Defaults in builder private final boolean mIsMetered; // Defaults in builder private final int mMaxMtu; // Defaults in builder + private final boolean mIsRestrictedToTestNetworks; private Ikev2VpnProfile( int type, @@ -116,7 +117,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { @NonNull List<String> allowedAlgorithms, boolean isBypassable, boolean isMetered, - int maxMtu) { + int maxMtu, + boolean restrictToTestNetworks) { super(type); checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address"); @@ -140,6 +142,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mIsBypassable = isBypassable; mIsMetered = isMetered; mMaxMtu = maxMtu; + mIsRestrictedToTestNetworks = restrictToTestNetworks; validate(); } @@ -329,6 +332,15 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { return mMaxMtu; } + /** + * Returns whether or not this VPN profile is restricted to test networks. + * + * @hide + */ + public boolean isRestrictedToTestNetworks() { + return mIsRestrictedToTestNetworks; + } + @Override public int hashCode() { return Objects.hash( @@ -345,7 +357,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mAllowedAlgorithms, mIsBypassable, mIsMetered, - mMaxMtu); + mMaxMtu, + mIsRestrictedToTestNetworks); } @Override @@ -368,7 +381,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms) && mIsBypassable == other.mIsBypassable && mIsMetered == other.mIsMetered - && mMaxMtu == other.mMaxMtu; + && mMaxMtu == other.mMaxMtu + && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks; } /** @@ -381,7 +395,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { */ @NonNull public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException { - final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */); + final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */, + mIsRestrictedToTestNetworks); profile.type = mType; profile.server = mServerAddr; profile.ipsecIdentifier = mUserIdentity; @@ -449,6 +464,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { builder.setBypassable(profile.isBypassable); builder.setMetered(profile.isMetered); builder.setMaxMtu(profile.maxMtu); + if (profile.isRestrictedToTestNetworks) { + builder.restrictToTestNetworks(); + } switch (profile.type) { case TYPE_IKEV2_IPSEC_USER_PASS: @@ -621,6 +639,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { private boolean mIsBypassable = false; private boolean mIsMetered = true; private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; + private boolean mIsRestrictedToTestNetworks = false; /** * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN. @@ -842,6 +861,21 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { } /** + * Restricts this profile to use test networks (only). + * + * <p>This method is for testing only, and must not be used by apps. Calling + * provisionVpnProfile() with a profile where test-network usage is enabled will require the + * MANAGE_TEST_NETWORKS permission. + * + * @hide + */ + @NonNull + public Builder restrictToTestNetworks() { + mIsRestrictedToTestNetworks = true; + return this; + } + + /** * Validates, builds and provisions the VpnProfile. * * @throws IllegalArgumentException if any of the required keys or values were invalid @@ -862,7 +896,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mAllowedAlgorithms, mIsBypassable, mIsMetered, - mMaxMtu); + mMaxMtu, + mIsRestrictedToTestNetworks); } } } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 74eced796b04..57d5d03a6cf2 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -677,16 +677,27 @@ public final class NetworkCapabilities implements Parcelable { * restrictions. * @hide */ - public void restrictCapabilitesForTestNetwork() { + public void restrictCapabilitesForTestNetwork(int creatorUid) { final long originalCapabilities = mNetworkCapabilities; final NetworkSpecifier originalSpecifier = mNetworkSpecifier; final int originalSignalStrength = mSignalStrength; + final int originalOwnerUid = getOwnerUid(); + final int[] originalAdministratorUids = getAdministratorUids(); clearAll(); // Reset the transports to only contain TRANSPORT_TEST. mTransportTypes = (1 << TRANSPORT_TEST); mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; mNetworkSpecifier = originalSpecifier; mSignalStrength = originalSignalStrength; + + // Only retain the owner and administrator UIDs if they match the app registering the remote + // caller that registered the network. + if (originalOwnerUid == creatorUid) { + setOwnerUid(creatorUid); + } + if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) { + setAdministratorUids(new int[] {creatorUid}); + } } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7923b586ada5..cadae5cecc6d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12061,17 +12061,6 @@ public final class Settings { public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants"; /** - * System VDSO global setting. This links to the "sys.vdso" system property. - * The following values are supported: - * false -> both 32 and 64 bit vdso disabled - * 32 -> 32 bit vdso enabled - * 64 -> 64 bit vdso enabled - * Any other value defaults to both 32 bit and 64 bit true. - * @hide - */ - public static final String SYS_VDSO = "sys_vdso"; - - /** * UidCpuPower global setting. This links the sys.uidcpupower system property. * The following values are supported: * 0 -> /proc/uid_cpupower/* are disabled diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 3a6c8dd3720f..489307beb878 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -189,12 +189,12 @@ public class Surface implements Parcelable { } /** - * Create a Surface assosciated with a given {@link SurfaceControl}. Buffers submitted to this + * Create a Surface associated with a given {@link SurfaceControl}. Buffers submitted to this * surface will be displayed by the system compositor according to the parameters * specified by the control. Multiple surfaces may be constructed from one SurfaceControl, * but only one can be connected (e.g. have an active EGL context) at a time. * - * @param from The SurfaceControl to assosciate this Surface with + * @param from The SurfaceControl to associate this Surface with */ public Surface(@NonNull SurfaceControl from) { copyFrom(from); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index fcd8127bbaa4..4f7bedaf1117 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2259,7 +2259,7 @@ public final class SurfaceControl implements Parcelable { } /** - * Specify how the buffer assosciated with this Surface is mapped in to the + * Specify how the buffer associated with this Surface is mapped in to the * parent coordinate space. The source frame will be scaled to fit the destination * frame, after being rotated according to the orientation parameter. * diff --git a/core/java/com/android/internal/compat/OWNERS b/core/java/com/android/internal/compat/OWNERS index 2b7cdb0cbce9..cfd0a4b079ad 100644 --- a/core/java/com/android/internal/compat/OWNERS +++ b/core/java/com/android/internal/compat/OWNERS @@ -2,6 +2,5 @@ platform-compat-eng+reviews@google.com andreionea@google.com -atrost@google.com mathewi@google.com satayev@google.com diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java index 829bd8a5a2a7..8ea5aa815a1c 100644 --- a/core/java/com/android/internal/net/VpnProfile.java +++ b/core/java/com/android/internal/net/VpnProfile.java @@ -136,13 +136,19 @@ public final class VpnProfile implements Cloneable, Parcelable { public boolean isMetered = false; // 21 public int maxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; // 22 public boolean areAuthParamsInline = false; // 23 + public final boolean isRestrictedToTestNetworks; // 24 // Helper fields. @UnsupportedAppUsage public transient boolean saveLogin = false; public VpnProfile(String key) { + this(key, false); + } + + public VpnProfile(String key, boolean isRestrictedToTestNetworks) { this.key = key; + this.isRestrictedToTestNetworks = isRestrictedToTestNetworks; } @UnsupportedAppUsage @@ -171,6 +177,7 @@ public final class VpnProfile implements Cloneable, Parcelable { isMetered = in.readBoolean(); maxMtu = in.readInt(); areAuthParamsInline = in.readBoolean(); + isRestrictedToTestNetworks = in.readBoolean(); } /** @@ -220,6 +227,7 @@ public final class VpnProfile implements Cloneable, Parcelable { out.writeBoolean(isMetered); out.writeInt(maxMtu); out.writeBoolean(areAuthParamsInline); + out.writeBoolean(isRestrictedToTestNetworks); } /** @@ -237,12 +245,21 @@ public final class VpnProfile implements Cloneable, Parcelable { String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1); // Acceptable numbers of values are: // 14-19: Standard profile, with option for serverCert, proxy - // 24: Standard profile with serverCert, proxy and platform-VPN parameters. - if ((values.length < 14 || values.length > 19) && values.length != 24) { + // 24: Standard profile with serverCert, proxy and platform-VPN parameters + // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks + if ((values.length < 14 || values.length > 19) + && values.length != 24 && values.length != 25) { return null; } - VpnProfile profile = new VpnProfile(key); + final boolean isRestrictedToTestNetworks; + if (values.length >= 25) { + isRestrictedToTestNetworks = Boolean.parseBoolean(values[24]); + } else { + isRestrictedToTestNetworks = false; + } + + VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks); profile.name = values[0]; profile.type = Integer.parseInt(values[1]); if (profile.type < 0 || profile.type > TYPE_MAX) { @@ -283,6 +300,8 @@ public final class VpnProfile implements Cloneable, Parcelable { profile.areAuthParamsInline = Boolean.parseBoolean(values[23]); } + // isRestrictedToTestNetworks (values[24]) assigned as part of the constructor + profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty(); return profile; } catch (Exception e) { @@ -330,6 +349,7 @@ public final class VpnProfile implements Cloneable, Parcelable { builder.append(VALUE_DELIMITER).append(isMetered); builder.append(VALUE_DELIMITER).append(maxMtu); builder.append(VALUE_DELIMITER).append(areAuthParamsInline); + builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks); return builder.toString().getBytes(StandardCharsets.UTF_8); } @@ -421,7 +441,8 @@ public final class VpnProfile implements Cloneable, Parcelable { return Objects.hash( key, type, server, username, password, dnsServers, searchDomains, routes, mppe, l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert, - proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline); + proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline, + isRestrictedToTestNetworks); } /** Checks VPN profiles for interior equality. */ @@ -453,7 +474,8 @@ public final class VpnProfile implements Cloneable, Parcelable { && isBypassable == other.isBypassable && isMetered == other.isMetered && maxMtu == other.maxMtu - && areAuthParamsInline == other.areAuthParamsInline; + && areAuthParamsInline == other.areAuthParamsInline + && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks; } @NonNull diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 3d99b726e6fe..829e1f7d0d96 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -905,13 +905,8 @@ message GlobalSettingsProto { optional SettingProto storage_full_threshold_bytes = 4 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto storage_cache_percentage = 5 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto storage_cache_max_bytes = 6 [ (android.privacy).dest = DEST_AUTOMATIC ]; - // System VDSO global setting. This links to the "sys.vdso" system property. - // The following values are supported: - // false -> both 32 and 64 bit vdso disabled - // 32 -> 32 bit vdso enabled - // 64 -> 64 bit vdso enabled - // Any other value defaults to both 32 bit and 64 bit true. - optional SettingProto vdso = 7 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Used to be sys_vdso + reserved 7; // UidCpuPower global setting. This links the sys.uidcpupower system property. // The following values are supported: // 0 -> /proc/uid_cpupower/* are disabled diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2ab44447fde2..6551b28bd5a3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -452,10 +452,6 @@ --> </string-array> - <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] --> - <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastservice - </string> - <!-- If the mobile hotspot feature requires provisioning, a package name and class name can be provided to launch a supported application that provisions the devices. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a844d8ae5a61..3cee3407296c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -745,7 +745,6 @@ <java-symbol type="string" name="config_ethernet_iface_regex" /> <java-symbol type="array" name="config_ethernet_interfaces" /> <java-symbol type="array" name="config_wakeonlan_supported_interfaces" /> - <java-symbol type="string" name="cellbroadcast_default_package" /> <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 70917e76f8b4..9cc04d341bdf 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -70,7 +70,7 @@ <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" /> <!-- Canada: 5-6 digits --> - <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" /> + <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" free="455677" /> <!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf --> <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" /> diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS index 2b7cdb0cbce9..cfd0a4b079ad 100644 --- a/core/tests/PlatformCompatFramework/OWNERS +++ b/core/tests/PlatformCompatFramework/OWNERS @@ -2,6 +2,5 @@ platform-compat-eng+reviews@google.com andreionea@google.com -atrost@google.com mathewi@google.com satayev@google.com diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 802b106a107c..cb91db1934a4 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -454,7 +454,6 @@ public class SettingsBackupTest { Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES, Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, - Settings.Global.SYS_VDSO, Settings.Global.SYS_UIDCPUPOWER, Settings.Global.SYS_TRACED, Settings.Global.FPS_DEVISOR, diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index a1c8e1366803..5b0ef8ef2130 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -291,6 +291,7 @@ applications that come with the platform <permission name="android.permission.MANAGE_DEVICE_ADMINS"/> <permission name="android.permission.MANAGE_USB"/> <permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> + <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp new file mode 100644 index 000000000000..94e6a8096849 --- /dev/null +++ b/data/fonts/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2011 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. + +prebuilt_font { + name: "DroidSansMono.ttf", + src: "DroidSansMono.ttf", + required: [ + "DroidSans.ttf", + "DroidSans-Bold.ttf", + ], +} + +prebuilt_font { + name: "AndroidClock.ttf", + src: "AndroidClock.ttf", +} + +///////////////////////////////// +// Copies the font configuration file into system/etc for the product as fonts.xml. +// Additional fonts should be installed to /product/fonts/ alongside a corresponding +// fonts_customiztion.xml in /product/etc/ +prebuilt_etc { + name: "fonts.xml", + src: "fonts.xml", +} diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index 4226e0882538..e22b72346249 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -12,9 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# We have to use BUILD_PREBUILT instead of PRODUCT_COPY_FIES, -# because MINIMAL_FONT_FOOTPRINT is only available in Android.mks. - LOCAL_PATH := $(call my-dir) ########################################## @@ -37,61 +34,7 @@ endef ########################################## $(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf)) $(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf)) -$(eval $(call create-font-symlink,DroidSerif-Regular.ttf,NotoSerif-Regular.ttf)) -$(eval $(call create-font-symlink,DroidSerif-Bold.ttf,NotoSerif-Bold.ttf)) -$(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf)) -$(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf)) - -extra_font_files := \ - DroidSans.ttf \ - DroidSans-Bold.ttf - -################################ -# Use DroidSansMono to hang extra_font_files on -include $(CLEAR_VARS) -LOCAL_MODULE := DroidSansMono.ttf -LOCAL_SRC_FILES := $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts -LOCAL_REQUIRED_MODULES := $(extra_font_files) -include $(BUILD_PREBUILT) -extra_font_files := - -################################ -# Build the rest of font files as prebuilt. - -# $(1): The source file name in LOCAL_PATH. -# It also serves as the module name and the dest file name. -define build-one-font-module -$(eval include $(CLEAR_VARS))\ -$(eval LOCAL_MODULE := $(1))\ -$(eval LOCAL_SRC_FILES := $(1))\ -$(eval LOCAL_MODULE_CLASS := ETC)\ -$(eval LOCAL_MODULE_TAGS := optional)\ -$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\ -$(eval include $(BUILD_PREBUILT)) -endef - -font_src_files := \ - AndroidClock.ttf - -$(foreach f, $(font_src_files), $(call build-one-font-module, $(f))) - -build-one-font-module := -font_src_files := - -################################ -# Copies the font configuration file into system/etc for the product as fonts.xml. -# Additional fonts should be installed to /product/fonts/ alongside a corresponding -# fonts_customiztion.xml in /product/etc/ -include $(CLEAR_VARS) - -LOCAL_MODULE := fonts.xml -LOCAL_MODULE_CLASS := ETC -LOCAL_PREBUILT_MODULE_FILE := frameworks/base/data/fonts/fonts.xml -include $(BUILD_PREBUILT) # Run sanity tests on fonts on checkbuild checkbuild: fontchain_lint diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 21129f927873..65f68cc5c5b5 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1352,9 +1352,6 @@ class SettingsProtoDumpUtil { Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, GlobalSettingsProto.Sys.STORAGE_CACHE_MAX_BYTES); dumpSetting(s, p, - Settings.Global.SYS_VDSO, - GlobalSettingsProto.Sys.VDSO); - dumpSetting(s, p, Settings.Global.SYS_UIDCPUPOWER, GlobalSettingsProto.Sys.UIDCPUPOWER); p.end(sysToken); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index ff91c797e9b1..24d089677eac 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -219,6 +219,9 @@ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/> <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/> + <!-- Permission required for CTS test - BatterySaverTest --> + <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/> + <!-- Permission required for CTS test - UiModeManagerTest --> <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/> @@ -247,6 +250,9 @@ <!-- Permission required for testing system audio effect APIs. --> <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/> + <!-- Permissions needed to test shared libraries --> + <uses-permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 29660a9c4dce..eb72b81fb766 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -114,6 +114,7 @@ android_app { // InProcessTethering is a replacement for Tethering overrides: ["Tethering"], apex_available: ["com.android.tethering"], + min_sdk_version: "current", } // Updatable tethering packaged as an application diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index 7ac9d251e1bb..79a178297aa5 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -13,49 +13,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -// AIDL interfaces between the core system and the tethering mainline module. -aidl_interface { - name: "tethering-aidl-interfaces", - unstable: true, - local_include_dir: "src", - include_dirs: ["frameworks/base/core/java"], // For framework parcelables. - srcs: [ - // @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: { - enabled: false, - }, - cpp: { - enabled: false, - }, - java: { - apex_available: [ - "//apex_available:platform", - "com.android.tethering", - ], - }, - }, -} - java_library { name: "framework-tethering", sdk_version: "module_current", srcs: [ - "src/android/net/TetheredClient.java", - "src/android/net/TetheringManager.java", - "src/android/net/TetheringConstants.java", - ], - static_libs: [ - "tethering-aidl-interfaces-java", + ":framework-tethering-srcs", ], jarjar_rules: "jarjar-rules.txt", installable: true, diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index c99922196346..3f5bc901d07b 100644 --- a/packages/Tethering/res/values/config.xml +++ b/packages/Tethering/res/values/config.xml @@ -55,6 +55,12 @@ <item>"bt-pan"</item> </string-array> + <!-- Use the BPF offload for tethering when the kernel has support. True by default. + If the device doesn't want to support tether BPF offload, this should be false. + Note that this setting could be overridden by device config. + --> + <bool translatable="false" name="config_tether_enable_bpf_offload">true</bool> + <!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. --> <bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool> diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml index 4c78a74d5358..4e2bb1e31b2a 100644 --- a/packages/Tethering/res/values/overlayable.xml +++ b/packages/Tethering/res/values/overlayable.xml @@ -23,6 +23,11 @@ <item type="array" name="config_tether_wifi_p2p_regexs"/> <item type="array" name="config_tether_bluetooth_regexs"/> <item type="array" name="config_tether_dhcp_range"/> + <!-- Use the BPF offload for tethering when the kernel has support. True by default. + If the device doesn't want to support tether BPF offload, this should be false. + Note that this setting could be overridden by device config. + --> + <item type="bool" name="config_tether_enable_bpf_offload"/> <item type="bool" name="config_tether_enable_legacy_dhcp_server"/> <item type="integer" name="config_tether_offload_poll_interval"/> <item type="array" name="config_tether_upstream_types"/> diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index 4f8ad8a221ef..4710a30b2998 100644 --- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -173,6 +173,18 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { return this; } + /** + * Set whether the DHCP server should request a new prefix from IpServer when receiving + * DHCPDECLINE message in certain particular link (e.g. there is only one downstream USB + * tethering client). If it's false, process DHCPDECLINE message as RFC2131#4.3.3 suggests. + * + * <p>If not set, the default value is false. + */ + public DhcpServingParamsParcelExt setChangePrefixOnDecline(boolean changePrefixOnDecline) { + this.changePrefixOnDecline = changePrefixOnDecline; + return this; + } + private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { int[] res = new int[addrs.size()]; int i = 0; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 83727bcdc67e..de537871a776 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -50,6 +50,7 @@ import android.net.shared.NetdUtils; import android.net.shared.RouteUtils; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; +import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -60,6 +61,7 @@ import android.util.Log; import android.util.SparseArray; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; @@ -115,6 +117,15 @@ public class IpServer extends StateMachine { private static final String ETHERNET_IFACE_ADDR = "192.168.50.1"; private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24; + // TODO: remove this constant after introducing PrivateAddressCoordinator. + private static final List<IpPrefix> NCM_PREFIXES = Collections.unmodifiableList( + Arrays.asList( + new IpPrefix("192.168.42.0/24"), + new IpPrefix("192.168.51.0/24"), + new IpPrefix("192.168.52.0/24"), + new IpPrefix("192.168.53.0/24") + )); + // TODO: have PanService use some visible version of this constant private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; @@ -212,6 +223,8 @@ public class IpServer extends StateMachine { public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10; // new neighbor cache entry on our interface public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11; + // request from DHCP server that it wants to have a new prefix + public static final int CMD_NEW_PREFIX_REQUEST = BASE_IPSERVER + 12; private final State mInitialState; private final State mLocalHotspotState; @@ -227,6 +240,7 @@ public class IpServer extends StateMachine { private final int mInterfaceType; private final LinkProperties mLinkProperties; private final boolean mUsingLegacyDhcp; + private final boolean mUsingBpfOffload; private final Dependencies mDeps; @@ -302,9 +316,12 @@ public class IpServer extends StateMachine { private final IpNeighborMonitor mIpNeighborMonitor; + // TODO: Add a dependency object to pass the data members or variables from the tethering + // object. It helps to reduce the arguments of the constructor. public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) { + INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload, + Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; @@ -314,6 +331,7 @@ public class IpServer extends StateMachine { mInterfaceType = interfaceType; mLinkProperties = new LinkProperties(); mUsingLegacyDhcp = usingLegacyDhcp; + mUsingBpfOffload = usingBpfOffload; mDeps = deps; resetLinkProperties(); mLastError = TetheringManager.TETHER_ERROR_NO_ERROR; @@ -321,7 +339,12 @@ public class IpServer extends StateMachine { mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog, new MyNeighborEventConsumer()); - if (!mIpNeighborMonitor.start()) { + + // IP neighbor monitor monitors the neighbor events for adding/removing offload + // forwarding rules per client. If BPF offload is not supported, don't start listening + // for neighbor events. See updateIpv6ForwardingRules, addIpv6ForwardingRule, + // removeIpv6ForwardingRule. + if (mUsingBpfOffload && !mIpNeighborMonitor.start()) { mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName); } @@ -452,7 +475,7 @@ public class IpServer extends StateMachine { handleError(); } } - }, new DhcpLeaseCallback()); + }, new DhcpEventCallback()); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -465,7 +488,7 @@ public class IpServer extends StateMachine { } } - private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub { + private class DhcpEventCallback extends IDhcpEventCallbacks.Stub { @Override public void onLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables) { final ArrayList<TetheredClient> leases = new ArrayList<>(); @@ -499,8 +522,9 @@ public class IpServer extends StateMachine { } @Override - public void onNewPrefixRequest(IpPrefix currentPrefix) { - //TODO: add specific implementation. + public void onNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { + Objects.requireNonNull(currentPrefix); + sendMessage(CMD_NEW_PREFIX_REQUEST, currentPrefix); } @Override @@ -514,26 +538,38 @@ public class IpServer extends StateMachine { } } + private RouteInfo getDirectConnectedRoute(@NonNull final LinkAddress ipv4Address) { + Objects.requireNonNull(ipv4Address); + return new RouteInfo(PrefixUtils.asIpPrefix(ipv4Address), null, mIfaceName, RTN_UNICAST); + } + + private DhcpServingParamsParcel makeServingParams(@NonNull final Inet4Address defaultRouter, + @NonNull final Inet4Address dnsServer, @NonNull LinkAddress serverAddr, + @Nullable Inet4Address clientAddr) { + final boolean changePrefixOnDecline = + (mInterfaceType == TetheringManager.TETHERING_NCM && clientAddr == null); + return new DhcpServingParamsParcelExt() + .setDefaultRouters(defaultRouter) + .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) + .setDnsServers(dnsServer) + .setServerAddr(serverAddr) + .setMetered(true) + .setSingleClientAddr(clientAddr) + .setChangePrefixOnDecline(changePrefixOnDecline); + // TODO: also advertise link MTU + } + private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) { if (mUsingLegacyDhcp) { return true; } final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress(); - final int prefixLen = serverLinkAddr.getPrefixLength(); final Inet4Address clientAddr = clientLinkAddr == null ? null : (Inet4Address) clientLinkAddr.getAddress(); - final DhcpServingParamsParcel params; - params = new DhcpServingParamsParcelExt() - .setDefaultRouters(addr) - .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) - .setDnsServers(addr) - .setServerAddr(serverLinkAddr) - .setMetered(true) - .setSingleClientAddr(clientAddr); - // TODO: also advertise link MTU - + final DhcpServingParamsParcel params = makeServingParams(addr /* defaultRouter */, + addr /* dnsServer */, serverLinkAddr, clientAddr); mDhcpServerStartIndex++; mDeps.makeDhcpServer( mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex)); @@ -560,7 +596,7 @@ public class IpServer extends StateMachine { }); mDhcpServer = null; } catch (RemoteException e) { - mLog.e("Error stopping DHCP", e); + mLog.e("Error stopping DHCP server", e); // Not much more we can do here } } @@ -642,31 +678,33 @@ public class IpServer extends StateMachine { return false; } - // Directly-connected route. - final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), - mIpv4Address.getPrefixLength()); - final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST); if (enabled) { mLinkProperties.addLinkAddress(mIpv4Address); - mLinkProperties.addRoute(route); + mLinkProperties.addRoute(getDirectConnectedRoute(mIpv4Address)); } else { mLinkProperties.removeLinkAddress(mIpv4Address); - mLinkProperties.removeRoute(route); + mLinkProperties.removeRoute(getDirectConnectedRoute(mIpv4Address)); } - return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } - private String getRandomWifiIPv4Address() { + private Inet4Address getRandomIPv4Address(@NonNull final byte[] rawAddr) { + final byte[] ipv4Addr = rawAddr; + ipv4Addr[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); try { - byte[] bytes = parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress(); - bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); - return InetAddress.getByAddress(bytes).getHostAddress(); - } catch (Exception e) { - return WIFI_HOST_IFACE_ADDR; + return (Inet4Address) InetAddress.getByAddress(ipv4Addr); + } catch (UnknownHostException e) { + mLog.e("Failed to construct Inet4Address from raw IPv4 addr"); + return null; } } + private String getRandomWifiIPv4Address() { + final Inet4Address ipv4Addr = + getRandomIPv4Address(parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress()); + return ipv4Addr != null ? ipv4Addr.getHostAddress() : WIFI_HOST_IFACE_ADDR; + } + private boolean startIPv6() { mInterfaceParams = mDeps.getInterfaceParams(mIfaceName); if (mInterfaceParams == null) { @@ -715,12 +753,12 @@ public class IpServer extends StateMachine { final String upstreamIface = v6only.getInterfaceName(); params = new RaParams(); - // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14, - // the ethernet header size. This makes kernel ebpf tethering offload happy. - // This hack should be reverted once we have the kernel fixed up. + // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest + // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering + // offload happy. This hack should be reverted once we have the kernel fixed up. // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu) // see RouterAdvertisementDaemon.java putMtu() - params.mtu = v6only.getMtu() - 16; + params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu(); params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface); @@ -751,21 +789,43 @@ public class IpServer extends StateMachine { mLastIPv6UpstreamIfindex = upstreamIfindex; } + private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) { + final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( + mNetd, toBeRemoved); + if (removalFailures > 0) { + mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", + removalFailures)); + } + + for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); + } + + private void addRoutesToLocalNetwork(@NonNull final List<RouteInfo> toBeAdded) { + try { + // It's safe to call networkAddInterface() even if + // the interface is already in the local_network. + mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); + try { + // Add routes from local network. Note that adding routes that + // already exist does not cause an error (EEXIST is silently ignored). + RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); + } catch (IllegalStateException e) { + mLog.e("Failed to add IPv4/v6 routes to local table: " + e); + return; + } + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to add " + mIfaceName + " to local table: ", e); + return; + } + + for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); + } + private void configureLocalIPv6Routes( HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) { // [1] Remove the routes that are deprecated. if (!deprecatedPrefixes.isEmpty()) { - final ArrayList<RouteInfo> toBeRemoved = - getLocalRoutesFor(mIfaceName, deprecatedPrefixes); - // Remove routes from local network. - final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork( - mNetd, toBeRemoved); - if (removalFailures > 0) { - mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", - removalFailures)); - } - - for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); + removeRoutesFromLocalNetwork(getLocalRoutesFor(mIfaceName, deprecatedPrefixes)); } // [2] Add only the routes that have not previously been added. @@ -776,24 +836,7 @@ public class IpServer extends StateMachine { } if (!addedPrefixes.isEmpty()) { - final ArrayList<RouteInfo> toBeAdded = - getLocalRoutesFor(mIfaceName, addedPrefixes); - try { - // It's safe to call networkAddInterface() even if - // the interface is already in the local_network. - mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName); - try { - // Add routes from local network. Note that adding routes that - // already exist does not cause an error (EEXIST is silently ignored). - RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded); - } catch (IllegalStateException e) { - mLog.e("Failed to add IPv6 routes to local table: " + e); - } - } catch (ServiceSpecificException | RemoteException e) { - mLog.e("Failed to add " + mIfaceName + " to local table: ", e); - } - - for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); + addRoutesToLocalNetwork(getLocalRoutesFor(mIfaceName, addedPrefixes)); } } } @@ -844,6 +887,11 @@ public class IpServer extends StateMachine { } private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) { + // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF + // offload is disabled. Add this check just in case. + // TODO: Perhaps remove this protection check. + if (!mUsingBpfOffload) return; + try { mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); mIpv6ForwardingRules.put(rule.address, rule); @@ -853,6 +901,11 @@ public class IpServer extends StateMachine { } private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { + // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF + // offload is disabled. Add this check just in case. + // TODO: Perhaps remove this protection check. + if (!mUsingBpfOffload) return; + try { mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); if (removeFromMap) { @@ -925,6 +978,80 @@ public class IpServer extends StateMachine { } } + // TODO: call PrivateAddressCoordinator.requestDownstreamAddress instead of this temporary + // logic. + private Inet4Address requestDownstreamAddress(@NonNull final IpPrefix currentPrefix) { + final int oldIndex = NCM_PREFIXES.indexOf(currentPrefix); + if (oldIndex == -1) { + mLog.e("current prefix isn't supported for NCM link: " + currentPrefix); + return null; + } + + final IpPrefix newPrefix = NCM_PREFIXES.get((oldIndex + 1) % NCM_PREFIXES.size()); + return getRandomIPv4Address(newPrefix.getRawAddress()); + } + + private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) { + if (!currentPrefix.contains(mIpv4Address.getAddress()) + || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) { + Log.e(TAG, "Invalid prefix: " + currentPrefix); + return; + } + + final LinkAddress deprecatedLinkAddress = mIpv4Address; + final Inet4Address srvAddr = requestDownstreamAddress(currentPrefix); + if (srvAddr == null) { + mLog.e("Fail to request a new downstream prefix"); + return; + } + mIpv4Address = new LinkAddress(srvAddr, currentPrefix.getPrefixLength()); + + // Add new IPv4 address on the interface. + if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) { + mLog.e("Failed to add new IP " + srvAddr); + return; + } + + // Remove deprecated routes from local network. + removeRoutesFromLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress))); + mLinkProperties.removeLinkAddress(deprecatedLinkAddress); + + // Add new routes to local network. + addRoutesToLocalNetwork( + Collections.singletonList(getDirectConnectedRoute(mIpv4Address))); + mLinkProperties.addLinkAddress(mIpv4Address); + + // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't + // listen on the interface configured with new IPv4 address, that results DNS validation + // failure of downstream client even if appropriate routes have been configured. + try { + mNetd.tetherApplyDnsInterfaces(); + } catch (ServiceSpecificException | RemoteException e) { + mLog.e("Failed to update local DNS caching server"); + return; + } + sendLinkProperties(); + + // Notify DHCP server that new prefix/route has been applied on IpServer. + final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null : + (Inet4Address) mStaticIpv4ClientAddr.getAddress(); + final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */, + srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr); + try { + mDhcpServer.updateParams(params, new OnHandlerStatusCallback() { + @Override + public void callback(int statusCode) { + if (statusCode != STATUS_SUCCESS) { + mLog.e("Error updating DHCP serving params: " + statusCode); + } + } + }); + } catch (RemoteException e) { + mLog.e("Error updating DHCP serving params", e); + } + } + private byte getHopLimit(String upstreamIface) { try { int upstreamHopLimit = Integer.parseUnsignedInt( @@ -1036,11 +1163,9 @@ public class IpServer extends StateMachine { } try { - final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(), - mIpv4Address.getPrefixLength()); - NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix); + NetdUtils.tetherInterface(mNetd, mIfaceName, PrefixUtils.asIpPrefix(mIpv4Address)); } catch (RemoteException | ServiceSpecificException | IllegalStateException e) { - mLog.e("Error Tethering: " + e); + mLog.e("Error Tethering", e); mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR; return; } @@ -1095,6 +1220,9 @@ public class IpServer extends StateMachine { mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR; transitionTo(mInitialState); break; + case CMD_NEW_PREFIX_REQUEST: + handleNewPrefixRequest((IpPrefix) message.obj); + break; default: return false; } diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 293f8eae32d5..fe92204c25c8 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -66,6 +66,7 @@ public class OffloadHardwareInterface { private final Handler mHandler; private final SharedLog mLog; + private final Dependencies mDeps; private IOffloadControl mOffloadControl; private TetheringOffloadCallback mTetheringOffloadCallback; private ControlCallback mControlCallback; @@ -126,8 +127,76 @@ public class OffloadHardwareInterface { } public OffloadHardwareInterface(Handler h, SharedLog log) { + this(h, log, new Dependencies(log)); + } + + OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) { mHandler = h; mLog = log.forSubComponent(TAG); + mDeps = deps; + } + + /** Capture OffloadHardwareInterface dependencies, for injection. */ + static class Dependencies { + private final SharedLog mLog; + + Dependencies(SharedLog log) { + mLog = log; + } + + public IOffloadConfig getOffloadConfig() { + try { + return IOffloadConfig.getService(true /*retry*/); + } catch (RemoteException | NoSuchElementException e) { + mLog.e("getIOffloadConfig error " + e); + return null; + } + } + + public IOffloadControl getOffloadControl() { + try { + return IOffloadControl.getService(true /*retry*/); + } catch (RemoteException | NoSuchElementException e) { + mLog.e("tethering offload control not supported: " + e); + return null; + } + } + + public NativeHandle createConntrackSocket(final int groups) { + final FileDescriptor fd; + try { + fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); + } catch (ErrnoException e) { + mLog.e("Unable to create conntrack socket " + e); + return null; + } + + final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); + try { + Os.bind(fd, sockAddr); + } catch (ErrnoException | SocketException e) { + mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); + try { + SocketUtils.closeSocket(fd); + } catch (IOException ie) { + // Nothing we can do here + } + return null; + } + try { + Os.connect(fd, sockAddr); + } catch (ErrnoException | SocketException e) { + mLog.e("connect to kernel fail for groups " + groups + " error: " + e); + try { + SocketUtils.closeSocket(fd); + } catch (IOException ie) { + // Nothing we can do here + } + return null; + } + + return new NativeHandle(fd, true); + } } /** Get default value indicating whether offload is supported. */ @@ -141,13 +210,7 @@ public class OffloadHardwareInterface { * share them with offload management process. */ public boolean initOffloadConfig() { - IOffloadConfig offloadConfig; - try { - offloadConfig = IOffloadConfig.getService(true /*retry*/); - } catch (RemoteException | NoSuchElementException e) { - mLog.e("getIOffloadConfig error " + e); - return false; - } + final IOffloadConfig offloadConfig = mDeps.getOffloadConfig(); if (offloadConfig == null) { mLog.e("Could not find IOffloadConfig service"); return false; @@ -159,11 +222,11 @@ public class OffloadHardwareInterface { // // h2 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). - final NativeHandle h1 = createConntrackSocket( + final NativeHandle h1 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; - final NativeHandle h2 = createConntrackSocket( + final NativeHandle h2 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { closeFdInNativeHandle(h1); @@ -198,53 +261,12 @@ public class OffloadHardwareInterface { } } - private NativeHandle createConntrackSocket(final int groups) { - FileDescriptor fd; - try { - fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); - } catch (ErrnoException e) { - mLog.e("Unable to create conntrack socket " + e); - return null; - } - - final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); - try { - Os.bind(fd, sockAddr); - } catch (ErrnoException | SocketException e) { - mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); - try { - SocketUtils.closeSocket(fd); - } catch (IOException ie) { - // Nothing we can do here - } - return null; - } - try { - Os.connect(fd, sockAddr); - } catch (ErrnoException | SocketException e) { - mLog.e("connect to kernel fail for groups " + groups + " error: " + e); - try { - SocketUtils.closeSocket(fd); - } catch (IOException ie) { - // Nothing we can do here - } - return null; - } - - return new NativeHandle(fd, true); - } - /** Initialize the tethering offload HAL. */ public boolean initOffloadControl(ControlCallback controlCb) { mControlCallback = controlCb; if (mOffloadControl == null) { - try { - mOffloadControl = IOffloadControl.getService(true /*retry*/); - } catch (RemoteException | NoSuchElementException e) { - mLog.e("tethering offload control not supported: " + e); - return false; - } + mOffloadControl = mDeps.getOffloadControl(); if (mOffloadControl == null) { mLog.e("tethering IOffloadControl.getService() returned null"); return false; diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index d1440a7c7be9..3ce3b4506c3f 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -109,8 +109,10 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceSpecificException; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -228,6 +230,7 @@ public class Tethering { private final ConnectedClientsTracker mConnectedClientsTracker; private final TetheringThreadExecutor mExecutor; private final TetheringNotificationUpdater mNotificationUpdater; + private final UserManager mUserManager; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. private ITetheringEventCallback mTetheringEventCallback = null; @@ -305,23 +308,24 @@ public class Tethering { mStateReceiver = new StateReceiver(); - final UserManager userManager = (UserManager) mContext.getSystemService( - Context.USER_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mTetheringRestriction = new UserRestrictionActionListener( - userManager, this, mNotificationUpdater); + mUserManager, this, mNotificationUpdater); mExecutor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor); mNetdCallback = new NetdCallback(); // Load tethering configuration. updateConfiguration(); + + startStateMachineUpdaters(); } /** * Start to register callbacks. * Call this function when tethering is ready to handle callback events. */ - public void startStateMachineUpdaters() { + private void startStateMachineUpdaters() { try { mNetd.registerUnsolicitedEventListener(mNetdCallback); } catch (RemoteException e) { @@ -779,7 +783,7 @@ public class Tethering { // TODO: Figure out how to update for local hotspot mode interfaces. private void sendTetherStateChangedBroadcast() { - if (!mDeps.isTetheringSupported()) return; + if (!isTetheringSupported()) return; final ArrayList<String> availableList = new ArrayList<>(); final ArrayList<String> tetherList = new ArrayList<>(); @@ -1020,14 +1024,14 @@ public class Tethering { @VisibleForTesting protected static class UserRestrictionActionListener { - private final UserManager mUserManager; + private final UserManager mUserMgr; private final Tethering mWrapper; private final TetheringNotificationUpdater mNotificationUpdater; public boolean mDisallowTethering; public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper, @NonNull TetheringNotificationUpdater updater) { - mUserManager = um; + mUserMgr = um; mWrapper = wrapper; mNotificationUpdater = updater; mDisallowTethering = false; @@ -1037,7 +1041,7 @@ public class Tethering { // getUserRestrictions gets restriction for this process' user, which is the primary // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary // user. See UserManager.DISALLOW_CONFIG_TETHERING. - final Bundle restrictions = mUserManager.getUserRestrictions(); + final Bundle restrictions = mUserMgr.getUserRestrictions(); final boolean newlyDisallowed = restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); final boolean prevDisallowed = mDisallowTethering; @@ -1988,7 +1992,7 @@ public class Tethering { mHandler.post(() -> { mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission)); final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel(); - parcel.tetheringSupported = mDeps.isTetheringSupported(); + parcel.tetheringSupported = isTetheringSupported(); parcel.upstreamNetwork = mTetherUpstream; parcel.config = mConfig.toStableParcelable(); parcel.states = @@ -2111,6 +2115,20 @@ public class Tethering { } } + // if ro.tether.denied = true we default to no tethering + // gservices could set the secure setting to 1 though to enable it on a build where it + // had previously been turned off. + boolean isTetheringSupported() { + final int defaultVal = + SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; + final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; + final boolean tetherEnabledInSettings = tetherSupported + && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); + + return tetherEnabledInSettings && hasTetherableConfiguration(); + } + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) { // Binder.java closes the resource for us. @SuppressWarnings("resource") @@ -2296,7 +2314,7 @@ public class Tethering { final TetherState tetherState = new TetherState( new IpServer(iface, mLooper, interfaceType, mLog, mNetd, makeControlCallback(), mConfig.enableLegacyDhcpServer, - mDeps.getIpServerDependencies())); + mConfig.enableBpfOffload, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); tetherState.ipServer.start(); } diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 9d4e74732729..48a600dfe6e1 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -73,6 +73,12 @@ public class TetheringConfiguration { private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; /** + * Override enabling BPF offload configuration for tethering. + */ + public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD = + "override_tether_enable_bpf_offload"; + + /** * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. */ public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = @@ -95,6 +101,8 @@ public class TetheringConfiguration { public final String[] legacyDhcpRanges; public final String[] defaultIPv4DNS; public final boolean enableLegacyDhcpServer; + // TODO: Add to TetheringConfigurationParcel if required. + public final boolean enableBpfOffload; public final String[] provisioningApp; public final String provisioningAppNoUi; @@ -124,11 +132,12 @@ public class TetheringConfiguration { isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean( - res, R.bool.config_tether_upstream_automatic); + res, R.bool.config_tether_upstream_automatic, false /** defaultValue */); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); + enableBpfOffload = getEnableBpfOffload(res); enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); @@ -208,6 +217,9 @@ public class TetheringConfiguration { pw.print("provisioningAppNoUi: "); pw.println(provisioningAppNoUi); + pw.print("enableBpfOffload: "); + pw.println(enableBpfOffload); + pw.print("enableLegacyDhcpServer: "); pw.println(enableLegacyDhcpServer); } @@ -228,6 +240,7 @@ public class TetheringConfiguration { toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); + sj.add(String.format("enableBpfOffload:%s", enableBpfOffload)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); return String.format("TetheringConfiguration{%s}", sj.toString()); } @@ -332,11 +345,11 @@ public class TetheringConfiguration { } } - private static boolean getResourceBoolean(Resources res, int resId) { + private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) { try { return res.getBoolean(resId); } catch (Resources.NotFoundException e404) { - return false; + return defaultValue; } } @@ -357,14 +370,36 @@ public class TetheringConfiguration { } } + private boolean getEnableBpfOffload(final Resources res) { + // Get BPF offload config + // Priority 1: Device config + // Priority 2: Resource config + // Priority 3: Default value + final boolean defaultValue = getResourceBoolean( + res, R.bool.config_tether_enable_bpf_offload, true /** default value */); + + return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue); + } + private boolean getEnableLegacyDhcpServer(final Resources res) { - return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server) - || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); + return getResourceBoolean( + res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */) + || getDeviceConfigBoolean( + TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */); + } + + private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) { + // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead + // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the + // returned boolean value comes from device config or default value (because of null + // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java. + final String value = getDeviceConfigProperty(name); + return value != null ? Boolean.parseBoolean(value) : defaultValue; } @VisibleForTesting - protected boolean getDeviceConfigBoolean(final String name) { - return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */); + protected String getDeviceConfigProperty(String name) { + return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name); } private Resources getResources(Context ctx, int subId) { diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java index af349f2b92a2..7d012738425b 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -40,15 +40,12 @@ import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.ip.IpServer; -import android.net.util.SharedLog; import android.os.Binder; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.SystemProperties; -import android.os.UserManager; import android.provider.Settings; import android.util.Log; @@ -68,21 +65,14 @@ import java.io.PrintWriter; public class TetheringService extends Service { private static final String TAG = TetheringService.class.getSimpleName(); - private final SharedLog mLog = new SharedLog(TAG); private TetheringConnector mConnector; - private Context mContext; - private TetheringDependencies mDeps; - private Tethering mTethering; - private UserManager mUserManager; @Override public void onCreate() { - mLog.mark("onCreate"); - mDeps = getTetheringDependencies(); - mContext = mDeps.getContext(); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mTethering = makeTethering(mDeps); - mTethering.startStateMachineUpdaters(); + final TetheringDependencies deps = makeTetheringDependencies(); + // The Tethering object needs a fully functional context to start, so this can't be done + // in the constructor. + mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this); } /** @@ -94,21 +84,10 @@ public class TetheringService extends Service { return new Tethering(deps); } - /** - * Create a binder connector for the system server to communicate with the tethering. - */ - private synchronized IBinder makeConnector() { - if (mConnector == null) { - mConnector = new TetheringConnector(mTethering, TetheringService.this); - } - return mConnector; - } - @NonNull @Override public IBinder onBind(Intent intent) { - mLog.mark("onBind"); - return makeConnector(); + return mConnector; } private static class TetheringConnector extends ITetheringConnector.Stub { @@ -248,7 +227,7 @@ public class TetheringService extends Service { listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); return true; } - if (!mService.isTetheringSupported()) { + if (!mTethering.isTetheringSupported()) { listener.onResult(TETHER_ERROR_UNSUPPORTED); return true; } @@ -266,7 +245,7 @@ public class TetheringService extends Service { receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null); return true; } - if (!mService.isTetheringSupported()) { + if (!mTethering.isTetheringSupported()) { receiver.send(TETHER_ERROR_UNSUPPORTED, null); return true; } @@ -300,20 +279,6 @@ public class TetheringService extends Service { } } - // if ro.tether.denied = true we default to no tethering - // gservices could set the secure setting to 1 though to enable it on a build where it - // had previously been turned off. - private boolean isTetheringSupported() { - final int defaultVal = - SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1; - final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; - final boolean tetherEnabledInSettings = tetherSupported - && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - - return tetherEnabledInSettings && mTethering.hasTetherableConfiguration(); - } - /** * Check if the package is a allowed to write settings. This also accounts that such an access * happened. @@ -332,87 +297,79 @@ public class TetheringService extends Service { * An injection method for testing. */ @VisibleForTesting - public TetheringDependencies getTetheringDependencies() { - if (mDeps == null) { - mDeps = new TetheringDependencies() { - @Override - public NetworkRequest getDefaultNetworkRequest() { - // TODO: b/147280869, add a proper system API to replace this. - final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() - .clearCapabilities() - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - return trackDefaultRequest; - } - - @Override - public Looper getTetheringLooper() { - final HandlerThread tetherThread = new HandlerThread("android.tethering"); - tetherThread.start(); - return tetherThread.getLooper(); - } + public TetheringDependencies makeTetheringDependencies() { + return new TetheringDependencies() { + @Override + public NetworkRequest getDefaultNetworkRequest() { + // TODO: b/147280869, add a proper system API to replace this. + final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + return trackDefaultRequest; + } - @Override - public boolean isTetheringSupported() { - return TetheringService.this.isTetheringSupported(); - } + @Override + public Looper getTetheringLooper() { + final HandlerThread tetherThread = new HandlerThread("android.tethering"); + tetherThread.start(); + return tetherThread.getLooper(); + } - @Override - public Context getContext() { - return TetheringService.this; - } + @Override + public Context getContext() { + return TetheringService.this; + } - @Override - public IpServer.Dependencies getIpServerDependencies() { - return new IpServer.Dependencies() { - @Override - public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, - DhcpServerCallbacks cb) { + @Override + public IpServer.Dependencies getIpServerDependencies() { + return new IpServer.Dependencies() { + @Override + public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, + DhcpServerCallbacks cb) { + try { + final INetworkStackConnector service = getNetworkStackConnector(); + if (service == null) return; + + service.makeDhcpServer(ifName, params, cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to make dhcp server"); try { - final INetworkStackConnector service = getNetworkStackConnector(); - if (service == null) return; - - service.makeDhcpServer(ifName, params, cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to make dhcp server"); - try { - cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); - } catch (RemoteException re) { } - } + cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); + } catch (RemoteException re) { } } - }; - } + } + }; + } - // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring - // networkStackClient. - static final int NETWORKSTACK_TIMEOUT_MS = 60_000; - private INetworkStackConnector getNetworkStackConnector() { - IBinder connector; - try { - final long before = System.currentTimeMillis(); - while ((connector = NetworkStack.getService()) == null) { - if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { - Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); - return null; - } - Thread.sleep(200); + // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring + // networkStackClient. + static final int NETWORKSTACK_TIMEOUT_MS = 60_000; + private INetworkStackConnector getNetworkStackConnector() { + IBinder connector; + try { + final long before = System.currentTimeMillis(); + while ((connector = NetworkStack.getService()) == null) { + if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { + Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); + return null; } - } catch (InterruptedException e) { - Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); - return null; + Thread.sleep(200); } - return INetworkStackConnector.Stub.asInterface(connector); + } catch (InterruptedException e) { + Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector"); + return null; } + return INetworkStackConnector.Stub.asInterface(connector); + } - @Override - public BluetoothAdapter getBluetoothAdapter() { - return BluetoothAdapter.getDefaultAdapter(); - } - }; - } - return mDeps; + @Override + public BluetoothAdapter getBluetoothAdapter() { + return BluetoothAdapter.getDefaultAdapter(); + } + }; } } diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index f9be7b9d3664..cd1ff607b475 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.INetd.IF_STATE_UP; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; @@ -38,6 +39,7 @@ import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -67,6 +69,7 @@ import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetherOffloadRuleParcel; import android.net.dhcp.DhcpServingParamsParcel; +import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; import android.net.dhcp.IDhcpServerCallbacks; import android.net.ip.IpNeighborMonitor.NeighborEvent; @@ -94,6 +97,7 @@ import org.mockito.MockitoAnnotations; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Arrays; +import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest @@ -106,6 +110,7 @@ public class IpServerTest { private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1"; private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; private static final int DHCP_LEASE_TIME_SECS = 3600; + private static final boolean DEFAULT_USING_BPF_OFFLOAD = true; private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams( IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */); @@ -130,10 +135,11 @@ public class IpServerTest { private NeighborEventConsumer mNeighborEventConsumer; private void initStateMachine(int interfaceType) throws Exception { - initStateMachine(interfaceType, false /* usingLegacyDhcp */); + initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD); } - private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception { + private void initStateMachine(int interfaceType, boolean usingLegacyDhcp, + boolean usingBpfOffload) throws Exception { doAnswer(inv -> { final IDhcpServerCallbacks cb = inv.getArgument(2); new Thread(() -> { @@ -165,7 +171,7 @@ public class IpServerTest { mIpServer = new IpServer( IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, - mCallback, usingLegacyDhcp, mDependencies); + mCallback, usingLegacyDhcp, usingBpfOffload, mDependencies); mIpServer.start(); mNeighborEventConsumer = neighborCaptor.getValue(); @@ -179,12 +185,13 @@ public class IpServerTest { private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception { - initTetheredStateMachine(interfaceType, upstreamIface, false); + initTetheredStateMachine(interfaceType, upstreamIface, false, + DEFAULT_USING_BPF_OFFLOAD); } private void initTetheredStateMachine(int interfaceType, String upstreamIface, - boolean usingLegacyDhcp) throws Exception { - initStateMachine(interfaceType, usingLegacyDhcp); + boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception { + initStateMachine(interfaceType, usingLegacyDhcp, usingBpfOffload); dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); if (upstreamIface != null) { LinkProperties lp = new LinkProperties(); @@ -204,7 +211,8 @@ public class IpServerTest { when(mDependencies.getIpNeighborMonitor(any(), any(), any())) .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, - mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies); + mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD, + mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( @@ -493,8 +501,62 @@ public class IpServerTest { } @Test + public void startsDhcpServerOnNcm() throws Exception { + initStateMachine(TETHERING_NCM); + dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); + dispatchTetherConnectionChanged(UPSTREAM_IFACE); + + assertDhcpStarted(new IpPrefix("192.168.42.0/24")); + } + + @Test + public void testOnNewPrefixRequest() throws Exception { + initStateMachine(TETHERING_NCM); + dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); + + final IDhcpEventCallbacks eventCallbacks; + final ArgumentCaptor<IDhcpEventCallbacks> dhcpEventCbsCaptor = + ArgumentCaptor.forClass(IDhcpEventCallbacks.class); + verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), dhcpEventCbsCaptor.capture()); + eventCallbacks = dhcpEventCbsCaptor.getValue(); + assertDhcpStarted(new IpPrefix("192.168.42.0/24")); + + // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals + // onNewPrefixRequest callback. + eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24")); + mLooper.dispatchAll(); + + final ArgumentCaptor<LinkProperties> lpCaptor = + ArgumentCaptor.forClass(LinkProperties.class); + InOrder inOrder = inOrder(mNetd, mCallback); + inOrder.verify(mCallback).updateInterfaceState( + mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR); + inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); + // One for ipv4 route, one for ipv6 link local route. + inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), + any(), any()); + inOrder.verify(mNetd).tetherApplyDnsInterfaces(); + inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture()); + verifyNoMoreInteractions(mCallback); + + final LinkProperties linkProperties = lpCaptor.getValue(); + final List<LinkAddress> linkAddresses = linkProperties.getLinkAddresses(); + assertEquals(1, linkProperties.getLinkAddresses().size()); + assertEquals(1, linkProperties.getRoutes().size()); + final IpPrefix prefix = new IpPrefix(linkAddresses.get(0).getAddress(), + linkAddresses.get(0).getPrefixLength()); + assertNotEquals(prefix, new IpPrefix("192.168.42.0/24")); + + verify(mDhcpServer).updateParams(mDhcpParamsCaptor.capture(), any()); + assertDhcpServingParams(mDhcpParamsCaptor.getValue(), prefix); + } + + @Test public void doesNotStartDhcpServerIfDisabled() throws Exception { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD); dispatchTetherConnectionChanged(UPSTREAM_IFACE); verify(mDependencies, never()).makeDhcpServer(any(), any(), any()); @@ -577,7 +639,8 @@ public class IpServerTest { @Test public void addRemoveipv6ForwardingRules() throws Exception { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */); + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD); final int myIfindex = TEST_IFACE_PARAMS.index; final int notMyIfindex = myIfindex - 1; @@ -678,19 +741,73 @@ public class IpServerTest { reset(mNetd); } - private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { - verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); - verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( - any(), any()); - final DhcpServingParamsParcel params = mDhcpParamsCaptor.getValue(); + @Test + public void enableDisableUsingBpfOffload() throws Exception { + final int myIfindex = TEST_IFACE_PARAMS.index; + final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1"); + final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); + final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); + + reset(mNetd); + + // Expect that rules can be only added/removed when the BPF offload config is enabled. + // Note that the usingBpfOffload false case is not a realistic test case. Because IP + // neighbor monitor doesn't start if BPF offload is disabled, there should have no + // neighbor event listening. This is used for testing the protection check just in case. + // TODO: Perhaps remove this test once we don't need this check anymore. + for (boolean usingBpfOffload : new boolean[]{true, false}) { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + usingBpfOffload); + + // A neighbor is added. + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + if (usingBpfOffload) { + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); + } else { + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + } + reset(mNetd); + + // A neighbor is deleted. + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + if (usingBpfOffload) { + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); + } else { + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + } + reset(mNetd); + } + } + + @Test + public void doesNotStartIpNeighborMonitorIfBpfOffloadDisabled() throws Exception { + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + false /* usingBpfOffload */); + + // IP neighbor monitor doesn't start if BPF offload is disabled. + verify(mIpNeighborMonitor, never()).start(); + } + + private void assertDhcpServingParams(final DhcpServingParamsParcel params, + final IpPrefix prefix) { // Last address byte is random - assertTrue(expectedPrefix.contains(intToInet4AddressHTH(params.serverAddr))); - assertEquals(expectedPrefix.getPrefixLength(), params.serverAddrPrefixLength); + assertTrue(prefix.contains(intToInet4AddressHTH(params.serverAddr))); + assertEquals(prefix.getPrefixLength(), params.serverAddrPrefixLength); assertEquals(1, params.defaultRouters.length); assertEquals(params.serverAddr, params.defaultRouters[0]); assertEquals(1, params.dnsServers.length); assertEquals(params.serverAddr, params.dnsServers[0]); assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs); + if (mIpServer.interfaceType() == TETHERING_NCM) { + assertTrue(params.changePrefixOnDecline); + } + } + + private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception { + verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any()); + verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks( + any(), any()); + assertDhcpServingParams(mDhcpParamsCaptor.getValue(), expectedPrefix); } /** diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index cdd0e243e31f..72fa916b9e42 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -147,9 +147,8 @@ public final class EntitlementManagerTest { doReturn(false).when( () -> SystemProperties.getBoolean( eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean())); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn(null).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), anyString())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java new file mode 100644 index 000000000000..f8ff1cb29c23 --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -0,0 +1,215 @@ +/* + * 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 com.android.networkstack.tethering; + +import static android.net.util.TetheringUtils.uint16; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; +import android.hardware.tetheroffload.control.V1_0.IOffloadControl; +import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; +import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; +import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; +import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.NativeHandle; +import android.os.test.TestLooper; +import android.system.OsConstants; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class OffloadHardwareInterfaceTest { + private static final String RMNET0 = "test_rmnet_data0"; + + private final TestLooper mTestLooper = new TestLooper(); + + private OffloadHardwareInterface mOffloadHw; + private ITetheringOffloadCallback mTetheringOffloadCallback; + private OffloadHardwareInterface.ControlCallback mControlCallback; + + @Mock private IOffloadConfig mIOffloadConfig; + @Mock private IOffloadControl mIOffloadControl; + @Mock private NativeHandle mNativeHandle; + + class MyDependencies extends OffloadHardwareInterface.Dependencies { + MyDependencies(SharedLog log) { + super(log); + } + + @Override + public IOffloadConfig getOffloadConfig() { + return mIOffloadConfig; + } + + @Override + public IOffloadControl getOffloadControl() { + return mIOffloadControl; + } + + @Override + public NativeHandle createConntrackSocket(final int groups) { + return mNativeHandle; + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + final SharedLog log = new SharedLog("test"); + mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log, + new MyDependencies(log)); + mControlCallback = spy(new OffloadHardwareInterface.ControlCallback()); + } + + private void startOffloadHardwareInterface() throws Exception { + mOffloadHw.initOffloadConfig(); + mOffloadHw.initOffloadControl(mControlCallback); + final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor = + ArgumentCaptor.forClass(ITetheringOffloadCallback.class); + verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any()); + mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue(); + } + + @Test + public void testGetForwardedStats() throws Exception { + startOffloadHardwareInterface(); + final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0); + verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any()); + assertNotNull(stats); + } + + @Test + public void testSetLocalPrefixes() throws Exception { + startOffloadHardwareInterface(); + final ArrayList<String> localPrefixes = new ArrayList<>(); + localPrefixes.add("127.0.0.0/8"); + localPrefixes.add("fe80::/64"); + mOffloadHw.setLocalPrefixes(localPrefixes); + verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any()); + } + + @Test + public void testSetDataLimit() throws Exception { + startOffloadHardwareInterface(); + final long limit = 12345; + mOffloadHw.setDataLimit(RMNET0, limit); + verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any()); + } + + @Test + public void testSetUpstreamParameters() throws Exception { + startOffloadHardwareInterface(); + final String v4addr = "192.168.10.1"; + final String v4gateway = "192.168.10.255"; + final ArrayList<String> v6gws = new ArrayList<>(0); + v6gws.add("2001:db8::1"); + mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws); + verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), + eq(v6gws), any()); + + final ArgumentCaptor<ArrayList<String>> mArrayListCaptor = + ArgumentCaptor.forClass(ArrayList.class); + mOffloadHw.setUpstreamParameters(null, null, null, null); + verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""), + mArrayListCaptor.capture(), any()); + assertEquals(mArrayListCaptor.getValue().size(), 0); + } + + @Test + public void testUpdateDownstreamPrefix() throws Exception { + startOffloadHardwareInterface(); + final String ifName = "wlan1"; + final String prefix = "192.168.43.0/24"; + mOffloadHw.addDownstreamPrefix(ifName, prefix); + verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any()); + + mOffloadHw.removeDownstreamPrefix(ifName, prefix); + verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any()); + } + + @Test + public void testTetheringOffloadCallback() throws Exception { + startOffloadHardwareInterface(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); + mTestLooper.dispatchAll(); + verify(mControlCallback).onStarted(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); + mTestLooper.dispatchAll(); + verify(mControlCallback).onStoppedError(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); + mTestLooper.dispatchAll(); + verify(mControlCallback).onStoppedUnsupported(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); + mTestLooper.dispatchAll(); + verify(mControlCallback).onSupportAvailable(); + + mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); + mTestLooper.dispatchAll(); + verify(mControlCallback).onStoppedLimitReached(); + + final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); + mTetheringOffloadCallback.updateTimeout(tcpParams); + mTestLooper.dispatchAll(); + verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), + eq(tcpParams.src.addr), + eq(uint16(tcpParams.src.port)), + eq(tcpParams.dst.addr), + eq(uint16(tcpParams.dst.port))); + + final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); + mTetheringOffloadCallback.updateTimeout(udpParams); + mTestLooper.dispatchAll(); + verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), + eq(udpParams.src.addr), + eq(uint16(udpParams.src.port)), + eq(udpParams.dst.addr), + eq(uint16(udpParams.dst.port))); + } + + private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { + final NatTimeoutUpdate params = new NatTimeoutUpdate(); + params.proto = proto; + params.src.addr = "192.168.43.200"; + params.src.port = 100; + params.dst.addr = "172.50.46.169"; + params.dst.port = 150; + return params; + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index e8ba5b8168d7..1999ad786ed4 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -30,7 +30,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; @@ -109,9 +108,9 @@ public class TetheringConfigurationTest { .mockStatic(DeviceConfig.class) .strictness(Strictness.WARN) .startMocking(); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn(null).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( new String[0]); @@ -127,6 +126,8 @@ public class TetheringConfigurationTest { .thenReturn(new String[0]); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); + initializeBpfOffloadConfiguration(true, null /* unset */); + mHasTelephonyManager = true; mMockContext = new MockContext(mContext); mEnableLegacyDhcpServer = false; @@ -278,13 +279,57 @@ public class TetheringConfigurationTest { assertFalse(upstreamIterator.hasNext()); } + private void initializeBpfOffloadConfiguration( + final boolean fromRes, final String fromDevConfig) { + when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); + doReturn(fromDevConfig).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); + } + + @Test + public void testBpfOffloadEnabledByResource() { + initializeBpfOffloadConfiguration(true, null /* unset */); + final TetheringConfiguration enableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadEnabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "true"); + final TetheringConfiguration enableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByDevConOverride.enableBpfOffload); + } + } + + @Test + public void testBpfOffloadDisabledByResource() { + initializeBpfOffloadConfiguration(false, null /* unset */); + final TetheringConfiguration disableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadDisabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "false"); + final TetheringConfiguration disableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByDevConOverride.enableBpfOffload); + } + } + @Test public void testNewDhcpServerDisabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( true); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("false").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration enableByRes = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -292,9 +337,9 @@ public class TetheringConfigurationTest { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn(true).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("true").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration enableByDevConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -305,9 +350,9 @@ public class TetheringConfigurationTest { public void testNewDhcpServerEnabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); - doReturn(false).when( - () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), - eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); + doReturn("false").when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER))); final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index 7df9fc685053..3dc6a1300de5 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -83,8 +83,7 @@ public final class TetheringServiceTest { mTetheringConnector = mockConnector.getTetheringConnector(); final MockTetheringService service = mockConnector.getService(); mTethering = service.getTethering(); - verify(mTethering).startStateMachineUpdaters(); - when(mTethering.hasTetherableConfiguration()).thenReturn(true); + when(mTethering.isTetheringSupported()).thenReturn(true); } @After @@ -97,7 +96,7 @@ public final class TetheringServiceTest { when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -109,7 +108,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -121,7 +120,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -133,7 +132,7 @@ public final class TetheringServiceTest { final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); } @@ -143,7 +142,7 @@ public final class TetheringServiceTest { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).stopTethering(TETHERING_WIFI); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -154,7 +153,7 @@ public final class TetheringServiceTest { final ResultReceiver result = new ResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); verifyNoMoreInteractions(mTethering); @@ -181,7 +180,7 @@ public final class TetheringServiceTest { public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verify(mTethering).untetherAll(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); @@ -191,7 +190,7 @@ public final class TetheringServiceTest { public void testIsTetheringSupported() throws Exception { final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).isTetheringSupported(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 85c2f2b984ae..7734a3c61eaf 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -312,8 +312,8 @@ public class TetheringTest { } @Override - protected boolean getDeviceConfigBoolean(final String name) { - return false; + protected String getDeviceConfigProperty(final String name) { + return null; } @Override @@ -485,18 +485,6 @@ public class TetheringTest { MockitoAnnotations.initMocks(this); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); - when(mResources.getStringArray(R.array.config_tether_usb_regexs)) - .thenReturn(new String[] { "test_rndis\\d" }); - when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) - .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) - .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); - when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) - .thenReturn(new String[0]); - when(mResources.getStringArray(R.array.config_tether_ncm_regexs)) - .thenReturn(new String[] { "test_ncm\\d" }); - when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); - when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); when(mNetd.interfaceGetList()) @@ -515,6 +503,7 @@ public class TetheringTest { mServiceContext = new TestContext(mContext); mContentResolver = new MockContentResolver(mServiceContext); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + setTetheringSupported(true /* supported */); mIntents = new Vector<>(); mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -525,7 +514,6 @@ public class TetheringTest { mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); mTethering = makeTethering(); - mTethering.startStateMachineUpdaters(); verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor = @@ -536,6 +524,31 @@ public class TetheringTest { mPhoneStateListener = phoneListenerCaptor.getValue(); } + private void setTetheringSupported(final boolean supported) { + Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, + supported ? 1 : 0); + when(mUserManager.hasUserRestriction( + UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported); + // Setup tetherable configuration. + when(mResources.getStringArray(R.array.config_tether_usb_regexs)) + .thenReturn(new String[] { "test_rndis\\d" }); + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) + .thenReturn(new String[]{ "test_wlan\\d" }); + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) + .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + when(mResources.getStringArray(R.array.config_tether_ncm_regexs)) + .thenReturn(new String[] { "test_ncm\\d" }); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true); + } + + private void initTetheringUpstream(UpstreamNetworkState upstreamState) { + when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); + when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + } + private Tethering makeTethering() { mTetheringDependencies.reset(); return new Tethering(mTetheringDependencies); @@ -672,9 +685,7 @@ public class TetheringTest { } private void prepareUsbTethering(UpstreamNetworkState upstreamState) { - when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); // Emulate pressing the USB tethering button in Settings UI. mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null); @@ -700,7 +711,7 @@ public class TetheringTest { verify(mNetd, times(1)).interfaceGetList(); // UpstreamNetworkMonitor should receive selected upstream - verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any()); + verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream(); verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network); } @@ -872,8 +883,7 @@ public class TetheringTest { // Then 464xlat comes up upstreamState = buildMobile464xlatUpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES. mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage( @@ -1344,9 +1354,7 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); // 2. Enable wifi tethering. UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); - when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())) - .thenReturn(upstreamState); + initTetheringUpstream(upstreamState); when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true); mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true); mLooper.dispatchAll(); @@ -1723,7 +1731,7 @@ public class TetheringTest { final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + initTetheringUpstream(upstreamState); stateMachine.chooseUpstreamType(true); verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network)); @@ -1735,7 +1743,7 @@ public class TetheringTest { final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM) mTetheringDependencies.mUpstreamNetworkMonitorMasterSM; final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); - when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState); + initTetheringUpstream(upstreamState); stateMachine.chooseUpstreamType(true); stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 08aab2aea6f9..635f184ce80c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2732,7 +2732,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the Messenger, but if this ever changes, not making a defensive copy // here will give attack vectors to clients using this code path. networkCapabilities = new NetworkCapabilities(networkCapabilities); - networkCapabilities.restrictCapabilitesForTestNetwork(); + networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid); } updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities); break; @@ -3079,10 +3079,6 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void notifyDataStallSuspected(DataStallReportParcelable p) { - final Message msg = mConnectivityDiagnosticsHandler.obtainMessage( - ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, - p.detectionMethod, mNetId, p.timestampMillis); - final PersistableBundle extras = new PersistableBundle(); switch (p.detectionMethod) { case DETECTION_METHOD_DNS_EVENTS: @@ -3097,12 +3093,9 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Unknown data stall detection method, ignoring: " + p.detectionMethod); return; } - msg.setData(new Bundle(extras)); - // NetworkStateTrackerHandler currently doesn't take any actions based on data - // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid - // the cost of going through two handlers. - mConnectivityDiagnosticsHandler.sendMessage(msg); + proxyDataStallToConnectivityDiagnosticsHandler( + p.detectionMethod, mNetId, p.timestampMillis, extras); } @Override @@ -3116,6 +3109,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void proxyDataStallToConnectivityDiagnosticsHandler(int detectionMethod, int netId, + long timestampMillis, @NonNull PersistableBundle extras) { + final Message msg = mConnectivityDiagnosticsHandler.obtainMessage( + ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, + detectionMethod, netId, timestampMillis); + msg.setData(new Bundle(extras)); + + // NetworkStateTrackerHandler currently doesn't take any actions based on data + // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid + // the cost of going through two handlers. + mConnectivityDiagnosticsHandler.sendMessage(msg); + } + private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) { return isPrivateDnsValidationRequired(nai.networkCapabilities); } @@ -5855,7 +5861,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the call to mixInCapabilities below anyway, but sanitizing here means the NAI never // sees capabilities that may be malicious, which might prevent mistakes in the future. networkCapabilities = new NetworkCapabilities(networkCapabilities); - networkCapabilities.restrictCapabilitesForTestNetwork(); + networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid()); } else { enforceNetworkFactoryPermission(); } @@ -5868,7 +5874,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), - this, mNetd, mDnsResolver, mNMS, providerId); + this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid()); // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says. nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc)); @@ -5969,7 +5975,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // Start or stop DNS64 detection and 464xlat according to network state. networkAgent.clatd.update(); notifyIfacesChangedForNetworkStats(); - networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp); + networkAgent.networkMonitor().notifyLinkPropertiesChanged( + new LinkProperties(newLp, true /* parcelSensitiveFields */)); if (networkAgent.everConnected) { notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); } @@ -7157,7 +7164,9 @@ public class ConnectivityService extends IConnectivityManager.Stub networkAgent.networkMonitor().setAcceptPartialConnectivity(); } networkAgent.networkMonitor().notifyNetworkConnected( - networkAgent.linkProperties, networkAgent.networkCapabilities); + new LinkProperties(networkAgent.linkProperties, + true /* parcelSensitiveFields */), + networkAgent.networkCapabilities); scheduleUnvalidatedPrompt(networkAgent); // Whether a particular NetworkRequest listen should cause signal strength thresholds to @@ -8155,4 +8164,24 @@ public class ConnectivityService extends IConnectivityManager.Stub 0, callback)); } + + @Override + public void simulateDataStall(int detectionMethod, long timestampMillis, + @NonNull Network network, @NonNull PersistableBundle extras) { + enforceAnyPermissionOf(android.Manifest.permission.MANAGE_TEST_NETWORKS, + android.Manifest.permission.NETWORK_STACK); + final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network); + if (!nc.hasTransport(TRANSPORT_TEST)) { + throw new SecurityException("Data Stall simluation is only possible for test networks"); + } + + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null || nai.creatorUid != Binder.getCallingUid()) { + throw new SecurityException("Data Stall simulation is only possible for network " + + "creators"); + } + + proxyDataStallToConnectivityDiagnosticsHandler( + detectionMethod, network.netId, timestampMillis, extras); + } } diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index 0ea73460e105..d6bd5a1d7c4c 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -317,39 +317,34 @@ class TestNetworkService extends ITestNetworkManager.Stub { "Cannot create network for non ipsec, non-testtun interface"); } - // Setup needs to be done with NETWORK_STACK privileges. - int callingUid = Binder.getCallingUid(); - Binder.withCleanCallingIdentity( - () -> { - try { - mNMS.setInterfaceUp(iface); - - // Synchronize all accesses to mTestNetworkTracker to prevent the case - // where: - // 1. TestNetworkAgent successfully binds to death of binder - // 2. Before it is added to the mTestNetworkTracker, binder dies, - // binderDied() is called (on a different thread) - // 3. This thread is pre-empted, put() is called after remove() - synchronized (mTestNetworkTracker) { - TestNetworkAgent agent = - registerTestNetworkAgent( - mHandler.getLooper(), - mContext, - iface, - lp, - isMetered, - callingUid, - administratorUids, - binder); - - mTestNetworkTracker.put(agent.getNetwork().netId, agent); - } - } catch (SocketException e) { - throw new UncheckedIOException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - }); + try { + // This requires NETWORK_STACK privileges. + Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface)); + + // Synchronize all accesses to mTestNetworkTracker to prevent the case where: + // 1. TestNetworkAgent successfully binds to death of binder + // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called + // (on a different thread) + // 3. This thread is pre-empted, put() is called after remove() + synchronized (mTestNetworkTracker) { + TestNetworkAgent agent = + registerTestNetworkAgent( + mHandler.getLooper(), + mContext, + iface, + lp, + isMetered, + Binder.getCallingUid(), + administratorUids, + binder); + + mTestNetworkTracker.put(agent.getNetwork().netId, agent); + } + } catch (SocketException e) { + throw new UncheckedIOException(e); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** Teardown a test network */ diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ece21f667418..166c4f3c749b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12857,7 +12857,9 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(" unmapped + "); pw.print(stringifyKBSize(ionPool)); pw.println(" pools)"); - kernelUsed += ionUnmapped; + // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being + // set on ION VMAs, therefore consider the entire ION heap as used kernel memory + kernelUsed += ionHeap; } final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() @@ -13594,7 +13596,9 @@ public class ActivityManagerService extends IActivityManager.Stub memInfoBuilder.append(" ION: "); memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool)); memInfoBuilder.append("\n"); - kernelUsed += ionUnmapped; + // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being + // set on ION VMAs, therefore consider the entire ION heap as used kernel memory + kernelUsed += ionHeap; } memInfoBuilder.append(" Used RAM: "); memInfoBuilder.append(stringifyKBSize( diff --git a/services/core/java/com/android/server/compat/OWNERS b/services/core/java/com/android/server/compat/OWNERS index 2b7cdb0cbce9..cfd0a4b079ad 100644 --- a/services/core/java/com/android/server/compat/OWNERS +++ b/services/core/java/com/android/server/compat/OWNERS @@ -2,6 +2,5 @@ platform-compat-eng+reviews@google.com andreionea@google.com -atrost@google.com mathewi@google.com satayev@google.com diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 2d1f553ab8cd..a9f62d91592d 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -168,6 +168,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // Obtained by ConnectivityService and merged into NetworkAgent-provided information. public CaptivePortalData captivePortalData; + // The UID of the remote entity that created this Network. + public final int creatorUid; + // Networks are lingered when they become unneeded as a result of their NetworkRequests being // satisfied by a higher-scoring network. so as to allow communication to wrap up before the // network is taken down. This usually only happens to the default network. Lingering ends with @@ -268,7 +271,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, 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) { + IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, + int creatorUid) { this.messenger = messenger; asyncChannel = ac; network = net; @@ -282,6 +286,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { mHandler = handler; networkAgentConfig = config; this.factorySerialNumber = factorySerialNumber; + this.creatorUid = creatorUid; } /** diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 0114b5bb1331..730da28ba8a2 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -65,6 +65,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; +import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.UidRange; import android.net.VpnManager; @@ -2225,12 +2226,27 @@ public class Vpn { @Override public void run() { - // Explicitly use only the network that ConnectivityService thinks is the "best." In - // other words, only ever use the currently selected default network. This does mean - // that in both onLost() and onConnected(), any old sessions MUST be torn down. This - // does NOT include VPNs. + // Unless the profile is restricted to test networks, explicitly use only the network + // that ConnectivityService thinks is the "best." In other words, only ever use the + // currently selected default network. This does mean that in both onLost() and + // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs. + // + // When restricted to test networks, select any network with TRANSPORT_TEST. Since the + // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS, + // this is considered safe. final ConnectivityManager cm = ConnectivityManager.from(mContext); - cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback); + final NetworkRequest req; + + if (mProfile.isRestrictedToTestNetworks()) { + req = new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build(); + } else { + req = cm.getDefaultRequest(); + } + + cm.requestNetwork(req, mNetworkCallback); } private boolean isActiveNetwork(@Nullable Network network) { @@ -2868,6 +2884,11 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + if (profile.isRestrictedToTestNetworks) { + mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS, + "Test-mode profiles require the MANAGE_TEST_NETWORKS permission"); + } + final byte[] encodedProfile = profile.encode(); if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) { throw new IllegalArgumentException("Profile too big"); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e21a01d2048f..5d1cc2a5c24a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -119,7 +119,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -160,6 +159,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -227,12 +227,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String PREFIX_UID_TAG = "uid_tag"; /** - * Virtual network interface for video telephony. This is for VT data usage counting purpose. - */ - // TODO: Remove this after no one is using it. - public static final String VT_INTERFACE = NetworkStats.IFACE_VT; - - /** * Settings that can be changed externally. */ public interface NetworkStatsSettings { @@ -304,8 +298,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DropBoxNonMonotonicObserver(); private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList = - new RemoteCallbackList<>(); + private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList = + new CopyOnWriteArrayList<>(); /** Semaphore used to wait for stats provider to respond to request stats update. */ private final Semaphore mStatsProviderSem = new Semaphore(0, true); @@ -1461,10 +1455,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. + // time to allow providers report-in given that normally binder call should be fast. Note + // that size of list might be changed because addition/removing at the same time. For + // addition, the stats of the missed provider can only be collected in next poll; + // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS + // once that happened. // TODO: request with a valid token. Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); + final int registeredCallbackCount = mStatsProviderCbList.size(); mStatsProviderSem.drainPermits(); invokeForAllStatsProviderCallbacks( (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); @@ -1638,7 +1636,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); + if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1929,7 +1927,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( tag, provider, mStatsProviderSem, mAlertObserver, mStatsProviderCbList); - mStatsProviderCbList.register(callback); + mStatsProviderCbList.add(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); return callback; @@ -1953,20 +1951,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void invokeForAllStatsProviderCallbacks( @NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) { - synchronized (mStatsLock) { - final int length = mStatsProviderCbList.beginBroadcast(); + for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { try { - for (int i = 0; i < length; i++) { - final NetworkStatsProviderCallbackImpl cb = - mStatsProviderCbList.getBroadcastItem(i); - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } finally { - mStatsProviderCbList.finishBroadcast(); + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); } } } @@ -1978,7 +1967,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final INetworkStatsProvider mProvider; @NonNull private final Semaphore mSemaphore; @NonNull final INetworkManagementEventObserver mAlertObserver; - @NonNull final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList; + @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList; @NonNull private final Object mProviderStatsLock = new Object(); @@ -1992,7 +1981,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, @NonNull INetworkManagementEventObserver alertObserver, - @NonNull RemoteCallbackList<NetworkStatsProviderCallbackImpl> cbList) + @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList) throws RemoteException { mTag = tag; mProvider = provider; @@ -2049,13 +2038,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void binderDied() { Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } @Override public void unregister() { Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } } diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index 4e14fd3d59a1..d9605522b3b0 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -106,6 +106,7 @@ public abstract class Conference extends Conferenceable { private int mCallerDisplayNamePresentation; private int mCallDirection; private boolean mRingbackRequested = false; + private boolean mIsMultiparty = true; private final Connection.Listener mConnectionDeathListener = new Connection.Listener() { @Override @@ -998,8 +999,8 @@ public abstract class Conference extends Conferenceable { public void onExtrasChanged(Bundle extras) {} /** - * Set whether Telecom should treat this {@link Conference} as a conference call or if it - * should treat it as a single-party call. + * Set whether Telecom should treat this {@link Conference} as a multiparty conference call or + * if it should treat it as a single-party call. * This method is used as part of a workaround regarding IMS conference calls and user * expectation. In IMS, once a conference is formed, the UE is connected to an IMS conference * server. If all participants of the conference drop out of the conference except for one, the @@ -1020,6 +1021,7 @@ public abstract class Conference extends Conferenceable { @TestApi @RequiresPermission(MODIFY_PHONE_STATE) public void setConferenceState(boolean isConference) { + mIsMultiparty = isConference; for (Listener l : mListeners) { l.onConferenceStateChanged(this, isConference); } @@ -1043,6 +1045,20 @@ public abstract class Conference extends Conferenceable { } } + /** + * Determines if the {@link Conference} is considered "multiparty" or not. By default all + * conferences are considered multiparty. A multiparty conference is one where there are + * multiple conference participants (other than the host) in the conference. + * This is tied to {@link #setConferenceState(boolean)}, which is used for some use cases to + * have a conference appear as if it is a standalone call, in which case the conference will + * no longer be multiparty. + * @return {@code true} if conference is treated as a conference (i.e. it is multiparty), + * {@code false} if it should emulate a standalone call (i.e. not multiparty). + * @hide + */ + public boolean isMultiparty() { + return mIsMultiparty; + } /** * Sets the address of this {@link Conference}. Used when {@link #setConferenceState(boolean)} diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 73296986d82e..1b60e4820ad0 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -2505,6 +2505,11 @@ public abstract class ConnectionService extends Service { mAdapter.addConferenceCall(id, parcelableConference); mAdapter.setVideoProvider(id, conference.getVideoProvider()); mAdapter.setVideoState(id, conference.getVideoState()); + // In some instances a conference can start its life as a standalone call with just a + // single participant; ensure we signal to Telecom in this case. + if (!conference.isMultiparty()) { + mAdapter.setConferenceState(id, conference.isMultiparty()); + } // Go through any child calls and set the parent. for (Connection connection : conference.getConnections()) { diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java index 0faa4fd2027a..31c24d54918a 100644 --- a/telecomm/java/android/telecom/GatewayInfo.java +++ b/telecomm/java/android/telecom/GatewayInfo.java @@ -111,7 +111,7 @@ public class GatewayInfo implements Parcelable { @Override public void writeToParcel(Parcel destination, int flags) { destination.writeString(mGatewayProviderPackageName); - mGatewayAddress.writeToParcel(destination, 0); - mOriginalAddress.writeToParcel(destination, 0); + Uri.writeToParcel(destination, mGatewayAddress); + Uri.writeToParcel(destination, mOriginalAddress); } } diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 415a817b58d5..182dc8bb8325 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -629,7 +629,7 @@ public final class ParcelableCall implements Parcelable { int capabilities = source.readInt(); int properties = source.readInt(); long connectTimeMillis = source.readLong(); - Uri handle = source.readParcelable(classLoader); + Uri handle = Uri.CREATOR.createFromParcel(source); int handlePresentation = source.readInt(); String callerDisplayName = source.readString(); int callerDisplayNamePresentation = source.readInt(); @@ -711,7 +711,7 @@ public final class ParcelableCall implements Parcelable { destination.writeInt(mCapabilities); destination.writeInt(mProperties); destination.writeLong(mConnectTimeMillis); - destination.writeParcelable(mHandle, 0); + Uri.writeToParcel(destination, mHandle); destination.writeInt(mHandlePresentation); destination.writeString(mCallerDisplayName); destination.writeInt(mCallerDisplayNamePresentation); diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java new file mode 100644 index 000000000000..6c6375586225 --- /dev/null +++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java @@ -0,0 +1,65 @@ +/* + * 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 com.android.internal.telephony; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.provider.Telephony; +import android.text.TextUtils; +import android.util.Log; + +/** + * This class provides utility functions related to CellBroadcast. + */ +public class CellBroadcastUtils { + private static final String TAG = "CellBroadcastUtils"; + private static final boolean VDBG = false; + + /** + * Utility method to query the default CBR's package name. + */ + public static String getDefaultCellBroadcastReceiverPackageName(Context context) { + PackageManager packageManager = context.getPackageManager(); + ResolveInfo resolveInfo = packageManager.resolveActivity( + new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION), + PackageManager.MATCH_SYSTEM_ONLY); + String packageName; + + if (resolveInfo == null) { + Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: no package found"); + return null; + } + + packageName = resolveInfo.activityInfo.applicationInfo.packageName; + + if (VDBG) { + Log.d(TAG, "getDefaultCellBroadcastReceiverPackageName: found package: " + packageName); + } + + if (TextUtils.isEmpty(packageName) || packageManager.checkPermission( + android.Manifest.permission.READ_CELL_BROADCASTS, packageName) + == PackageManager.PERMISSION_DENIED) { + Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: returning null; " + + "permission check failed for : " + packageName); + return null; + } + + return packageName; + } +} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 41bab25af115..4d15a93c2dbe 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4108,10 +4108,10 @@ public class CarrierConfigManager { }); sDefaults.putIntArray(KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY, new int[] { - -19, /* SIGNAL_STRENGTH_POOR */ + -20, /* SIGNAL_STRENGTH_POOR */ -17, /* SIGNAL_STRENGTH_MODERATE */ -14, /* SIGNAL_STRENGTH_GOOD */ - -12 /* SIGNAL_STRENGTH_GREAT */ + -11 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY, new int[] { @@ -4139,9 +4139,9 @@ public class CarrierConfigManager { // Boundaries: [-20 dB, -3 dB] new int[] { -16, /* SIGNAL_STRENGTH_POOR */ - -11, /* SIGNAL_STRENGTH_MODERATE */ + -12, /* SIGNAL_STRENGTH_MODERATE */ -9, /* SIGNAL_STRENGTH_GOOD */ - -7 /* SIGNAL_STRENGTH_GREAT */ + -6 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, // Boundaries: [-23 dB, 40 dB] diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index 8562df1d015f..95fe90a47654 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -57,9 +57,9 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa // Boundaries: [-20 dB, -3 dB] private int[] mSsRsrqThresholds = new int[] { -16, /* SIGNAL_STRENGTH_POOR */ - -11, /* SIGNAL_STRENGTH_MODERATE */ + -12, /* SIGNAL_STRENGTH_MODERATE */ -9, /* SIGNAL_STRENGTH_GOOD */ - -7 /* SIGNAL_STRENGTH_GREAT */ + -6 /* SIGNAL_STRENGTH_GREAT */ }; // Lifted from Default carrier configs and max range of SSSINR diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index a269bd1809d4..5c84297d3b86 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1392,15 +1392,16 @@ public class ServiceState implements Parcelable { /** @hide */ public boolean isUsingCarrierAggregation() { + boolean isUsingCa = false; NetworkRegistrationInfo nri = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (nri != null) { DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); if (dsri != null) { - return dsri.isUsingCarrierAggregation(); + isUsingCa = dsri.isUsingCarrierAggregation(); } } - return false; + return isUsingCa || getCellBandwidths().length > 1; } /** @hide */ diff --git a/test-base/api/lint-baseline.txt b/test-base/api/lint-baseline.txt new file mode 100644 index 000000000000..86c8a910d20a --- /dev/null +++ b/test-base/api/lint-baseline.txt @@ -0,0 +1,3 @@ +// Baseline format: 1.0 +MissingNullability: junit.framework.ComparisonFailure#getMessage(): + Missing nullability on method `getMessage` return diff --git a/test-mock/api/lint-baseline.txt b/test-mock/api/lint-baseline.txt new file mode 100644 index 000000000000..c6ba3f5d8fd8 --- /dev/null +++ b/test-mock/api/lint-baseline.txt @@ -0,0 +1,143 @@ +// Baseline format: 1.0 +ArrayReturn: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1: + Method parameter should be Collection<ContentValues> (or subclass) instead of raw array; was `android.content.ContentValues[]` +ArrayReturn: android.test.mock.MockResources#getTextArray(int): + Method should return Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]` + + +MissingNullability: android.test.mock.MockApplication#onConfigurationChanged(android.content.res.Configuration) parameter #0: + Missing nullability on parameter `newConfig` in method `onConfigurationChanged` +MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0: + Missing nullability on parameter `context` in method `attachInfo` +MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1: + Missing nullability on parameter `info` in method `attachInfo` +MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #0: + Missing nullability on parameter `uri` in method `bulkInsert` +MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1: + Missing nullability on parameter `values` in method `bulkInsert` +MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String): + Missing nullability on method `getStreamTypes` return +MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #0: + Missing nullability on parameter `url` in method `getStreamTypes` +MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #1: + Missing nullability on parameter `mimeTypeFilter` in method `getStreamTypes` +MissingNullability: android.test.mock.MockContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean) parameter #0: + Missing nullability on parameter `uri` in method `notifyChange` +MissingNullability: android.test.mock.MockContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean) parameter #1: + Missing nullability on parameter `observer` in method `notifyChange` +MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0: + Missing nullability on parameter `service` in method `bindIsolatedService` +MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2: + Missing nullability on parameter `instanceName` in method `bindIsolatedService` +MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3: + Missing nullability on parameter `executor` in method `bindIsolatedService` +MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4: + Missing nullability on parameter `conn` in method `bindIsolatedService` +MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0: + Missing nullability on parameter `service` in method `bindService` +MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2: + Missing nullability on parameter `executor` in method `bindService` +MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3: + Missing nullability on parameter `conn` in method `bindService` +MissingNullability: android.test.mock.MockContext#getMainExecutor(): + Missing nullability on method `getMainExecutor` return +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #0: + Missing nullability on parameter `intent` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #1: + Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #2: + Missing nullability on parameter `receiverAppOp` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #3: + Missing nullability on parameter `resultReceiver` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #4: + Missing nullability on parameter `scheduler` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #6: + Missing nullability on parameter `initialData` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #7: + Missing nullability on parameter `initialExtras` in method `sendOrderedBroadcast` +MissingNullability: android.test.mock.MockContext#updateServiceGroup(android.content.ServiceConnection, int, int) parameter #0: + Missing nullability on parameter `conn` in method `updateServiceGroup` +MissingNullability: android.test.mock.MockCursor#getNotificationUris(): + Missing nullability on method `getNotificationUris` return +MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #0: + Missing nullability on parameter `cr` in method `setNotificationUris` +MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #1: + Missing nullability on parameter `uris` in method `setNotificationUris` +MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int): + Missing nullability on method `getPackageArchiveInfo` return +MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int) parameter #0: + Missing nullability on parameter `archiveFilePath` in method `getPackageArchiveInfo` +MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #0: + Missing nullability on parameter `packageName` in method `hasSigningCertificate` +MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #1: + Missing nullability on parameter `certificate` in method `hasSigningCertificate` +MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(int, byte[], int) parameter #1: + Missing nullability on parameter `certificate` in method `hasSigningCertificate` +MissingNullability: android.test.mock.MockResources#getAnimation(int): + Missing nullability on method `getAnimation` return +MissingNullability: android.test.mock.MockResources#getConfiguration(): + Missing nullability on method `getConfiguration` return +MissingNullability: android.test.mock.MockResources#getDisplayMetrics(): + Missing nullability on method `getDisplayMetrics` return +MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #0: + Missing nullability on parameter `name` in method `getIdentifier` +MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #1: + Missing nullability on parameter `defType` in method `getIdentifier` +MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #2: + Missing nullability on parameter `defPackage` in method `getIdentifier` +MissingNullability: android.test.mock.MockResources#getIntArray(int): + Missing nullability on method `getIntArray` return +MissingNullability: android.test.mock.MockResources#getLayout(int): + Missing nullability on method `getLayout` return +MissingNullability: android.test.mock.MockResources#getQuantityString(int, int): + Missing nullability on method `getQuantityString` return +MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...): + Missing nullability on method `getQuantityString` return +MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...) parameter #2: + Missing nullability on parameter `formatArgs` in method `getQuantityString` +MissingNullability: android.test.mock.MockResources#getQuantityText(int, int): + Missing nullability on method `getQuantityText` return +MissingNullability: android.test.mock.MockResources#getResourceEntryName(int): + Missing nullability on method `getResourceEntryName` return +MissingNullability: android.test.mock.MockResources#getResourceName(int): + Missing nullability on method `getResourceName` return +MissingNullability: android.test.mock.MockResources#getResourcePackageName(int): + Missing nullability on method `getResourcePackageName` return +MissingNullability: android.test.mock.MockResources#getResourceTypeName(int): + Missing nullability on method `getResourceTypeName` return +MissingNullability: android.test.mock.MockResources#getString(int): + Missing nullability on method `getString` return +MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...): + Missing nullability on method `getString` return +MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...) parameter #1: + Missing nullability on parameter `formatArgs` in method `getString` +MissingNullability: android.test.mock.MockResources#getStringArray(int): + Missing nullability on method `getStringArray` return +MissingNullability: android.test.mock.MockResources#getText(int): + Missing nullability on method `getText` return +MissingNullability: android.test.mock.MockResources#getText(int, CharSequence): + Missing nullability on method `getText` return +MissingNullability: android.test.mock.MockResources#getText(int, CharSequence) parameter #1: + Missing nullability on parameter `def` in method `getText` +MissingNullability: android.test.mock.MockResources#getTextArray(int): + Missing nullability on method `getTextArray` return +MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #0: + Missing nullability on parameter `name` in method `getValue` +MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #1: + Missing nullability on parameter `outValue` in method `getValue` +MissingNullability: android.test.mock.MockResources#getValue(int, android.util.TypedValue, boolean) parameter #1: + Missing nullability on parameter `outValue` in method `getValue` +MissingNullability: android.test.mock.MockResources#getXml(int): + Missing nullability on method `getXml` return +MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]): + Missing nullability on method `obtainAttributes` return +MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #0: + Missing nullability on parameter `set` in method `obtainAttributes` +MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #1: + Missing nullability on parameter `attrs` in method `obtainAttributes` +MissingNullability: android.test.mock.MockResources#obtainTypedArray(int): + Missing nullability on method `obtainTypedArray` return +MissingNullability: android.test.mock.MockResources#openRawResource(int): + Missing nullability on method `openRawResource` return +MissingNullability: android.test.mock.MockResources#openRawResourceFd(int): + Missing nullability on method `openRawResourceFd` return diff --git a/test-mock/api/system-lint-baseline.txt b/test-mock/api/system-lint-baseline.txt new file mode 100644 index 000000000000..466bc5376ed6 --- /dev/null +++ b/test-mock/api/system-lint-baseline.txt @@ -0,0 +1,15 @@ +// Baseline format: 1.0 +IntentBuilderName: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler): + Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiverForAllUsers` + + +MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler): + Missing nullability on method `registerReceiverForAllUsers` return +MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #0: + Missing nullability on parameter `receiver` in method `registerReceiverForAllUsers` +MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #1: + Missing nullability on parameter `filter` in method `registerReceiverForAllUsers` +MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #2: + Missing nullability on parameter `broadcastPermission` in method `registerReceiverForAllUsers` +MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #3: + Missing nullability on parameter `scheduler` in method `registerReceiverForAllUsers` diff --git a/test-runner/api/lint-baseline.txt b/test-runner/api/lint-baseline.txt new file mode 100644 index 000000000000..54947fe687c0 --- /dev/null +++ b/test-runner/api/lint-baseline.txt @@ -0,0 +1,173 @@ +// Baseline format: 1.0 +GenericException: android.test.ActivityInstrumentationTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ActivityInstrumentationTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ActivityInstrumentationTestCase2#runTest(): + Methods must not throw generic exceptions (`java.lang.Throwable`) +GenericException: android.test.ActivityInstrumentationTestCase2#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ActivityInstrumentationTestCase2#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ActivityUnitTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ActivityUnitTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ApplicationTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ApplicationTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ProviderTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ProviderTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ProviderTestCase2#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ProviderTestCase2#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ServiceTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.ServiceTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.SingleLaunchActivityTestCase#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.SingleLaunchActivityTestCase#tearDown(): + Methods must not throw generic exceptions (`java.lang.Exception`) +GenericException: android.test.SyncBaseInstrumentation#setUp(): + Methods must not throw generic exceptions (`java.lang.Exception`) + + +IntentBuilderName: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter): + Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiver` + + +MissingNullability: android.test.ComparisonFailure#getMessage(): + Missing nullability on method `getMessage` return +MissingNullability: android.test.InstrumentationTestRunner#onCreate(android.os.Bundle) parameter #0: + Missing nullability on parameter `arguments` in method `onCreate` +MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0: + Missing nullability on parameter `service` in method `bindIsolatedService` +MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2: + Missing nullability on parameter `instanceName` in method `bindIsolatedService` +MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3: + Missing nullability on parameter `executor` in method `bindIsolatedService` +MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4: + Missing nullability on parameter `conn` in method `bindIsolatedService` +MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #0: + Missing nullability on parameter `service` in method `bindService` +MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #1: + Missing nullability on parameter `conn` in method `bindService` +MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0: + Missing nullability on parameter `service` in method `bindService` +MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2: + Missing nullability on parameter `executor` in method `bindService` +MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3: + Missing nullability on parameter `conn` in method `bindService` +MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #0: + Missing nullability on parameter `uri` in method `checkUriPermission` +MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #1: + Missing nullability on parameter `readPermission` in method `checkUriPermission` +MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #2: + Missing nullability on parameter `writePermission` in method `checkUriPermission` +MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, int, int, int) parameter #0: + Missing nullability on parameter `uri` in method `checkUriPermission` +MissingNullability: android.test.IsolatedContext#getContentResolver(): + Missing nullability on method `getContentResolver` return +MissingNullability: android.test.IsolatedContext#getFilesDir(): + Missing nullability on method `getFilesDir` return +MissingNullability: android.test.IsolatedContext#getSystemService(String): + Missing nullability on method `getSystemService` return +MissingNullability: android.test.IsolatedContext#getSystemService(String) parameter #0: + Missing nullability on parameter `name` in method `getSystemService` +MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter): + Missing nullability on method `registerReceiver` return +MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #0: + Missing nullability on parameter `receiver` in method `registerReceiver` +MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #1: + Missing nullability on parameter `filter` in method `registerReceiver` +MissingNullability: android.test.IsolatedContext#sendBroadcast(android.content.Intent) parameter #0: + Missing nullability on parameter `intent` in method `sendBroadcast` +MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #0: + Missing nullability on parameter `intent` in method `sendOrderedBroadcast` +MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #1: + Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast` +MissingNullability: android.test.IsolatedContext#unregisterReceiver(android.content.BroadcastReceiver) parameter #0: + Missing nullability on parameter `receiver` in method `unregisterReceiver` +MissingNullability: android.test.RenamingDelegatingContext#databaseList(): + Missing nullability on method `databaseList` return +MissingNullability: android.test.RenamingDelegatingContext#deleteDatabase(String) parameter #0: + Missing nullability on parameter `name` in method `deleteDatabase` +MissingNullability: android.test.RenamingDelegatingContext#deleteFile(String) parameter #0: + Missing nullability on parameter `name` in method `deleteFile` +MissingNullability: android.test.RenamingDelegatingContext#fileList(): + Missing nullability on method `fileList` return +MissingNullability: android.test.RenamingDelegatingContext#getCacheDir(): + Missing nullability on method `getCacheDir` return +MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String): + Missing nullability on method `getDatabasePath` return +MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String) parameter #0: + Missing nullability on parameter `name` in method `getDatabasePath` +MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String): + Missing nullability on method `getFileStreamPath` return +MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String) parameter #0: + Missing nullability on parameter `name` in method `getFileStreamPath` +MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String): + Missing nullability on method `openFileInput` return +MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String) parameter #0: + Missing nullability on parameter `name` in method `openFileInput` +MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int): + Missing nullability on method `openFileOutput` return +MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int) parameter #0: + Missing nullability on parameter `name` in method `openFileOutput` +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory): + Missing nullability on method `openOrCreateDatabase` return +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #0: + Missing nullability on parameter `name` in method `openOrCreateDatabase` +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #2: + Missing nullability on parameter `factory` in method `openOrCreateDatabase` +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler): + Missing nullability on method `openOrCreateDatabase` return +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #0: + Missing nullability on parameter `name` in method `openOrCreateDatabase` +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #2: + Missing nullability on parameter `factory` in method `openOrCreateDatabase` +MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #3: + Missing nullability on parameter `errorHandler` in method `openOrCreateDatabase` + + +ProtectedMember: android.test.ActivityInstrumentationTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.setUp()} +ProtectedMember: android.test.ActivityInstrumentationTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.tearDown()} +ProtectedMember: android.test.ActivityInstrumentationTestCase2#runTest(): + Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.runTest()} +ProtectedMember: android.test.ActivityInstrumentationTestCase2#setUp(): + Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.setUp()} +ProtectedMember: android.test.ActivityInstrumentationTestCase2#tearDown(): + Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.tearDown()} +ProtectedMember: android.test.ActivityUnitTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.setUp()} +ProtectedMember: android.test.ActivityUnitTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.tearDown()} +ProtectedMember: android.test.ApplicationTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.ApplicationTestCase.setUp()} +ProtectedMember: android.test.ApplicationTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.ApplicationTestCase.tearDown()} +ProtectedMember: android.test.ProviderTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.ProviderTestCase.setUp()} +ProtectedMember: android.test.ProviderTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.ProviderTestCase.tearDown()} +ProtectedMember: android.test.ProviderTestCase2#setUp(): + Protected methods not allowed; must be public: method android.test.ProviderTestCase2.setUp()} +ProtectedMember: android.test.ProviderTestCase2#tearDown(): + Protected methods not allowed; must be public: method android.test.ProviderTestCase2.tearDown()} +ProtectedMember: android.test.ServiceTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.ServiceTestCase.setUp()} +ProtectedMember: android.test.ServiceTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.ServiceTestCase.tearDown()} +ProtectedMember: android.test.SingleLaunchActivityTestCase#setUp(): + Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.setUp()} +ProtectedMember: android.test.SingleLaunchActivityTestCase#tearDown(): + Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.tearDown()} +ProtectedMember: android.test.SyncBaseInstrumentation#setUp(): + Protected methods not allowed; must be public: method android.test.SyncBaseInstrumentation.setUp()} diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java index ceca6f028866..e5daa71c30ea 100644 --- a/tests/net/java/com/android/internal/net/VpnProfileTest.java +++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java @@ -33,7 +33,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** Unit tests for {@link VpnProfile}. */ @SmallTest @@ -41,6 +43,9 @@ import java.util.Arrays; public class VpnProfileTest { private static final String DUMMY_PROFILE_KEY = "Test"; + private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23; + private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24; + @Test public void testDefaults() throws Exception { final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY); @@ -67,10 +72,11 @@ public class VpnProfileTest { assertFalse(p.isMetered); assertEquals(1360, p.maxMtu); assertFalse(p.areAuthParamsInline); + assertFalse(p.isRestrictedToTestNetworks); } private VpnProfile getSampleIkev2Profile(String key) { - final VpnProfile p = new VpnProfile(key); + final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */); p.name = "foo"; p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; @@ -116,7 +122,7 @@ public class VpnProfileTest { @Test public void testParcelUnparcel() { - assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22); + assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23); } @Test @@ -159,14 +165,41 @@ public class VpnProfileTest { assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues)); } + private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) { + // Sort to ensure when we remove, we can do it from greatest first. + Arrays.sort(missingIndices); + + final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode()); + final List<String> parts = + new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER))); + + // Remove from back first to ensure indexing is consistent. + for (int i = missingIndices.length - 1; i >= 0; i--) { + parts.remove(missingIndices[i]); + } + + return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0])); + } + @Test public void testEncodeDecodeInvalidNumberOfValues() { - final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY); - final String encoded = new String(profile.encode()); - final byte[] tooFewValues = - encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes(); + final String tooFewValues = + getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_AUTH_PARAMS_INLINE, + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); - assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues)); + assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes())); + } + + @Test + public void testEncodeDecodeMissingIsRestrictedToTestNetworks() { + final String tooFewValues = + getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); + + // Verify decoding without isRestrictedToTestNetworks defaults to false + final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); + assertFalse(decoded.isRestrictedToTestNetworks); } @Test diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 3282c76290cd..e66e26452602 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -75,6 +75,7 @@ import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.RouteInfo.RTN_UNREACHABLE; +import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType; @@ -7048,7 +7049,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithoutUid = new NetworkAgentInfo( null, null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0); + mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission( android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED); @@ -7064,7 +7065,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithoutUid = new NetworkAgentInfo( null, null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0); + mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7080,7 +7081,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithoutUid = new NetworkAgentInfo( null, null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0); + mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -7097,7 +7098,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithoutUid = new NetworkAgentInfo( null, null, network, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0); + mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -7131,7 +7132,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithUid = new NetworkAgentInfo( null, null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0); + mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -7153,7 +7154,7 @@ public class ConnectivityServiceTest { final NetworkAgentInfo naiWithUid = new NetworkAgentInfo( null, null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0); + mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_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 24a87177224e..aafa18a532fa 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -38,6 +38,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; +import android.os.Binder; import android.os.INetworkManagementService; import android.text.format.DateUtils; @@ -354,7 +355,7 @@ public class LingerMonitorTest { caps.addTransportType(transport); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, - NetworkProvider.ID_NONE); + NetworkProvider.ID_NONE, Binder.getCallingUid()); nai.everValidated = true; return nai; } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 77e2a6bb21de..e8970d48e404 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -1669,6 +1669,16 @@ class Linker { context_->SetCompilationPackage(app_info.package); } + // Determine the package name under which to merge resources. + if (options_.rename_resources_package) { + if (!options_.custom_java_package) { + // Generate the R.java under the original package name instead of the package name specified + // through --rename-resources-package. + options_.custom_java_package = context_->GetCompilationPackage(); + } + context_->SetCompilationPackage(options_.rename_resources_package.value()); + } + // Now that the compilation package is set, load the dependencies. This will also extract // the Android framework's versionCode and versionName, if they exist. if (!LoadSymbolsFromIncludePaths()) { |