diff options
180 files changed, 5593 insertions, 2304 deletions
diff --git a/Android.bp b/Android.bp index e39d1e74ce89..0407c41a16a7 100644 --- a/Android.bp +++ b/Android.bp @@ -674,7 +674,7 @@ java_defaults { "ext", ], - jarjar_rules: ":framework-hidl-jarjar", + jarjar_rules: "jarjar_rules_hidl.txt", static_libs: [ "apex_aidl_interface-java", @@ -684,18 +684,24 @@ java_defaults { "android.hardware.cas-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hardware.health-V1.0-java-constants", + "android.hardware.radio-V1.0-java", + "android.hardware.radio-V1.1-java", + "android.hardware.radio-V1.2-java", + "android.hardware.radio-V1.3-java", + "android.hardware.radio-V1.4-java", + "android.hardware.radio.config-V1.0-java", + "android.hardware.radio.config-V1.1-java", + "android.hardware.radio.config-V1.2-java", + "android.hardware.radio.deprecated-V1.0-java", "android.hardware.thermal-V1.0-java-constants", "android.hardware.tv.input-V1.0-java-constants", "android.hardware.usb-V1.0-java-constants", "android.hardware.usb-V1.1-java-constants", + "android.hardware.usb.gadget-V1.0-java", "android.hardware.vibrator-V1.0-java", "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.wifi-V1.0-java-constants", - "android.hardware.radio-V1.0-java", - "android.hardware.radio-V1.3-java", - "android.hardware.radio-V1.4-java", - "android.hardware.usb.gadget-V1.0-java", "networkstack-aidl-interfaces-java", "netd_aidl_interface-java", ], @@ -730,11 +736,6 @@ filegroup { ], } -filegroup { - name: "framework-hidl-jarjar", - srcs: ["jarjar_rules_hidl.txt"], -} - java_library { name: "framework", defaults: ["framework-defaults"], @@ -759,19 +760,6 @@ java_library_host { } // A temporary build target that is conditionally included on the bootclasspath if -// org.apache.http.legacy library has been removed and which provides support for -// maintaining backwards compatibility for APKs that target pre-P and depend on -// org.apache.http.legacy classes. This is used iff REMOVE_OAHL_FROM_BCP=true is -// specified on the build command line. -java_library { - name: "framework-oahl-backward-compatibility", - installable: true, - srcs: [ - "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java", - ], -} - -// A temporary build target that is conditionally included on the bootclasspath if // android.test.base library has been removed and which provides support for // maintaining backwards compatibility for APKs that target pre-P and depend on // android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is @@ -852,6 +840,32 @@ aidl_interface { api_dir: "aidl/networkstack", } +filegroup { + name: "framework-networkstack-shared-srcs", + srcs: [ + // TODO: remove these annotations as soon as we can use andoid.support.annotations.* + "core/java/android/annotation/NonNull.java", + "core/java/android/annotation/Nullable.java", + "core/java/android/annotation/IntDef.java", + "core/java/android/annotation/IntRange.java", + "core/java/android/annotation/UnsupportedAppUsage.java", + "core/java/android/net/DhcpResults.java", + "core/java/android/util/LocalLog.java", + "core/java/com/android/internal/annotations/GuardedBy.java", + "core/java/com/android/internal/annotations/VisibleForTesting.java", + "core/java/com/android/internal/util/HexDump.java", + "core/java/com/android/internal/util/IndentingPrintWriter.java", + "core/java/com/android/internal/util/IState.java", + "core/java/com/android/internal/util/MessageUtils.java", + "core/java/com/android/internal/util/Preconditions.java", + "core/java/com/android/internal/util/RingBufferIndices.java", + "core/java/com/android/internal/util/State.java", + "core/java/com/android/internal/util/StateMachine.java", + "core/java/com/android/internal/util/WakeupMessage.java", + "core/java/android/net/shared/*.java", + ] +} + // Build ext.jar // ============================================================ java_library { diff --git a/api/current.txt b/api/current.txt index 65b087204ea1..4363b6e753f9 100755 --- a/api/current.txt +++ b/api/current.txt @@ -6450,6 +6450,7 @@ package android.app.admin { method @Nullable public String[] getAccountTypesWithManagementDisabled(); method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins(); method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName); + method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName); method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName); method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String); method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName); @@ -6519,6 +6520,7 @@ package android.app.admin { method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(@NonNull android.content.ComponentName); method public boolean isAffiliatedUser(); + method public boolean isAlwaysOnVpnLockdownEnabled(@NonNull android.content.ComponentName); method public boolean isApplicationHidden(@NonNull android.content.ComponentName, String); method public boolean isBackupServiceEnabled(@NonNull android.content.ComponentName); method @Deprecated public boolean isCallerApplicationRestrictionsManagingPackage(); @@ -6555,7 +6557,8 @@ package android.app.admin { method @Nullable public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(@NonNull android.content.ComponentName); method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean); method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>); - method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException; + method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException; + method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean); method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle); method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -11197,7 +11200,7 @@ package android.content.pm { method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int); method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo); method public abstract android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException; - method public abstract int getApplicationEnabledSetting(String); + method public abstract int getApplicationEnabledSetting(@NonNull String); method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo); method public abstract android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -11205,7 +11208,7 @@ package android.content.pm { method public abstract android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo); method public abstract android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException; method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int); - method public abstract int getComponentEnabledSetting(android.content.ComponentName); + method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName); method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); method public abstract android.graphics.drawable.Drawable getDrawable(String, @DrawableRes int, android.content.pm.ApplicationInfo); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); @@ -11268,8 +11271,8 @@ package android.content.pm { method public abstract android.content.pm.ProviderInfo resolveContentProvider(String, int); method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public abstract void setApplicationCategoryHint(@NonNull String, int); - method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(String, int, int); - method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int); + method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int); + method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int); method public abstract void setInstallerPackageName(String, String); method public abstract void updateInstantAppCookie(@Nullable byte[]); method public abstract void verifyPendingInstall(int, int); @@ -27851,6 +27854,7 @@ package android.net { method public android.net.VpnService.Builder setBlocking(boolean); method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent); method public android.net.VpnService.Builder setHttpProxy(android.net.ProxyInfo); + method public android.net.VpnService.Builder setMetered(boolean); method public android.net.VpnService.Builder setMtu(int); method public android.net.VpnService.Builder setSession(String); method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]); @@ -29087,6 +29091,7 @@ package android.nfc { } public final class NfcAdapter { + method public boolean deviceSupportsNfcSecure(); method public void disableForegroundDispatch(android.app.Activity); method @Deprecated public void disableForegroundNdefPush(android.app.Activity); method public void disableReaderMode(android.app.Activity); @@ -29099,6 +29104,7 @@ package android.nfc { method @Deprecated public boolean invokeBeam(android.app.Activity); method public boolean isEnabled(); method @Deprecated public boolean isNdefPushEnabled(); + method public boolean isNfcSecureEnabled(); method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity); method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity); method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...); @@ -41151,6 +41157,7 @@ package android.telecom { method public static String capabilitiesToString(int); method public android.telecom.PhoneAccountHandle getAccountHandle(); method public int getCallCapabilities(); + method public int getCallDirection(); method @Nullable public android.telecom.CallIdentification getCallIdentification(); method public int getCallProperties(); method public String getCallerDisplayName(); @@ -41187,6 +41194,9 @@ package android.telecom { field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000 field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2 field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8 + field public static final int DIRECTION_INCOMING = 0; // 0x0 + field public static final int DIRECTION_OUTGOING = 1; // 0x1 + field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff field public static final int PROPERTY_CONFERENCE = 1; // 0x1 field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4 field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20 @@ -41954,8 +41964,8 @@ package android.telecom { } public static final class VideoProfile.CameraCapabilities implements android.os.Parcelable { - ctor public VideoProfile.CameraCapabilities(int, int); - ctor public VideoProfile.CameraCapabilities(int, int, boolean, float); + ctor public VideoProfile.CameraCapabilities(@IntRange(from=0) int, @IntRange(from=0) int); + ctor public VideoProfile.CameraCapabilities(@IntRange(from=0) int, @IntRange(from=0) int, boolean, @FloatRange(from=1.0f) float); method public int describeContents(); method public int getHeight(); method public float getMaxZoom(); @@ -42215,6 +42225,9 @@ package android.telephony { field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int"; field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; + field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long"; + field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG = "opportunistic_network_entry_or_exit_hysteresis_time_long"; + field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT = "opportunistic_network_entry_threshold_bandwidth_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int"; field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; @@ -42876,6 +42889,7 @@ package android.telephony { public class SubscriptionInfo implements android.os.Parcelable { method public android.graphics.Bitmap createIconBitmap(android.content.Context); method public int describeContents(); + method public int getCardId(); method public int getCarrierId(); method public CharSequence getCarrierName(); method public String getCountryIso(); @@ -42992,6 +43006,7 @@ package android.telephony { method public android.telephony.TelephonyManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); + method public int getCardIdForDefaultEuicc(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig(); method public int getCarrierIdFromSimMccMnc(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.CellLocation getCellLocation(); @@ -43039,6 +43054,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getSubscriberId(); method public String getTypeAllocationCode(); method public String getTypeAllocationCode(int); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(); @@ -43081,8 +43097,10 @@ package android.telephony { method public boolean setVoiceMailNumber(String, String); method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri); method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int); method public boolean updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>); field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL"; + field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED"; field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE"; @@ -43120,6 +43138,7 @@ package android.telephony { field public static final String EXTRA_INCOMING_NUMBER = "incoming_number"; field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH"; field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT"; + field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY"; field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT"; field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE"; field public static final String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID"; @@ -43130,6 +43149,7 @@ package android.telephony { field public static final String EXTRA_STATE_RINGING; field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID"; field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER"; + field public static final int INVALID_CARD_ID = -1; // 0xffffffff field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU"; field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 @@ -43197,6 +43217,18 @@ package android.telephony { method public void onResults(java.util.List<android.telephony.CellInfo>); } + public final class UiccCardInfo implements android.os.Parcelable { + ctor public UiccCardInfo(boolean, int, String, String, int); + method public int describeContents(); + method public int getCardId(); + method public String getEid(); + method public String getIccId(); + method public int getSlotIndex(); + method public boolean isEuicc(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR; + } + public abstract class VisualVoicemailService extends android.app.Service { ctor public VisualVoicemailService(); method public android.os.IBinder onBind(android.content.Intent); @@ -43352,6 +43384,7 @@ package android.telephony.emergency { method public java.util.List<java.lang.Integer> getEmergencyNumberSources(); method public java.util.List<java.lang.Integer> getEmergencyServiceCategories(); method public int getEmergencyServiceCategoryBitmask(); + method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); method public String getMnc(); method public String getNumber(); method public boolean isFromSources(int); @@ -55507,13 +55540,13 @@ package java.io { ctor public ByteArrayOutputStream(int); method public void reset(); method public int size(); - method public byte[] toByteArray(); + method @NonNull public byte[] toByteArray(); method @NonNull public String toString(@NonNull String) throws java.io.UnsupportedEncodingException; method @Deprecated @NonNull public String toString(int); method public void write(int); - method public void write(byte[], int, int); + method public void write(@NonNull byte[], int, int); method public void writeTo(@NonNull java.io.OutputStream) throws java.io.IOException; - field protected byte[] buf; + field @NonNull protected byte[] buf; field protected int count; } @@ -55684,12 +55717,12 @@ package java.io { method public boolean isHidden(); method public long lastModified(); method public long length(); - method public String[] list(); - method public String[] list(@Nullable java.io.FilenameFilter); - method public java.io.File[] listFiles(); - method public java.io.File[] listFiles(@Nullable java.io.FilenameFilter); - method public java.io.File[] listFiles(@Nullable java.io.FileFilter); - method public static java.io.File[] listRoots(); + method @Nullable public String[] list(); + method @Nullable public String[] list(@Nullable java.io.FilenameFilter); + method @Nullable public java.io.File[] listFiles(); + method @Nullable public java.io.File[] listFiles(@Nullable java.io.FilenameFilter); + method @Nullable public java.io.File[] listFiles(@Nullable java.io.FileFilter); + method @NonNull public static java.io.File[] listRoots(); method public boolean mkdir(); method public boolean mkdirs(); method public boolean renameTo(@NonNull java.io.File); @@ -56178,8 +56211,8 @@ package java.io { method protected void clearError(); method public void close(); method public void flush(); - method @NonNull public java.io.PrintWriter format(@NonNull String, java.lang.Object...); - method @NonNull public java.io.PrintWriter format(@Nullable java.util.Locale, @NonNull String, java.lang.Object...); + method @NonNull public java.io.PrintWriter format(@NonNull String, @NonNull java.lang.Object...); + method @NonNull public java.io.PrintWriter format(@Nullable java.util.Locale, @NonNull String, @NonNull java.lang.Object...); method public void print(boolean); method public void print(char); method public void print(int); @@ -56189,8 +56222,8 @@ package java.io { method public void print(char[]); method public void print(@Nullable String); method public void print(@Nullable Object); - method @NonNull public java.io.PrintWriter printf(@NonNull String, java.lang.Object...); - method @NonNull public java.io.PrintWriter printf(@Nullable java.util.Locale, @NonNull String, java.lang.Object...); + method @NonNull public java.io.PrintWriter printf(@NonNull String, @NonNull java.lang.Object...); + method @NonNull public java.io.PrintWriter printf(@Nullable java.util.Locale, @NonNull String, @NonNull java.lang.Object...); method public void println(); method public void println(boolean); method public void println(char); @@ -57016,45 +57049,45 @@ package java.lang { method @NonNull public static Class<?> forName(@NonNull String) throws java.lang.ClassNotFoundException; method @NonNull public static Class<?> forName(@NonNull String, boolean, @Nullable ClassLoader) throws java.lang.ClassNotFoundException; method @Nullable public <A extends java.lang.annotation.Annotation> A getAnnotation(@NonNull Class<A>); - method public java.lang.annotation.Annotation[] getAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getAnnotations(); method @NonNull public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(@NonNull Class<A>); method @Nullable public String getCanonicalName(); method @Nullable public ClassLoader getClassLoader(); - method public Class<?>[] getClasses(); + method @NonNull public Class<?>[] getClasses(); method @Nullable public Class<?> getComponentType(); - method @NonNull public java.lang.reflect.Constructor<T> getConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; - method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException; + method @NonNull public java.lang.reflect.Constructor<T> getConstructor(@Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; + method @NonNull public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException; method @Nullable public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(@NonNull Class<A>); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); - method public Class<?>[] getDeclaredClasses(); - method @NonNull public java.lang.reflect.Constructor<T> getDeclaredConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; - method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException; + method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method @NonNull public Class<?>[] getDeclaredClasses(); + method @NonNull public java.lang.reflect.Constructor<T> getDeclaredConstructor(@Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; + method @NonNull public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException; method @NonNull public java.lang.reflect.Field getDeclaredField(@NonNull String) throws java.lang.NoSuchFieldException; - method public java.lang.reflect.Field[] getDeclaredFields(); - method @NonNull public java.lang.reflect.Method getDeclaredMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; - method public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException; + method @NonNull public java.lang.reflect.Field[] getDeclaredFields(); + method @NonNull public java.lang.reflect.Method getDeclaredMethod(@NonNull String, @Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; + method @NonNull public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException; method @Nullable public Class<?> getDeclaringClass(); method @Nullable public Class<?> getEnclosingClass(); method @Nullable public java.lang.reflect.Constructor<?> getEnclosingConstructor(); method @Nullable public java.lang.reflect.Method getEnclosingMethod(); - method public T[] getEnumConstants(); + method @Nullable public T[] getEnumConstants(); method @NonNull public java.lang.reflect.Field getField(@NonNull String) throws java.lang.NoSuchFieldException; - method public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException; - method public java.lang.reflect.Type[] getGenericInterfaces(); + method @NonNull public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException; + method @NonNull public java.lang.reflect.Type[] getGenericInterfaces(); method @Nullable public java.lang.reflect.Type getGenericSuperclass(); - method public Class<?>[] getInterfaces(); - method @NonNull public java.lang.reflect.Method getMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; - method public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException; + method @NonNull public Class<?>[] getInterfaces(); + method @NonNull public java.lang.reflect.Method getMethod(@NonNull String, @Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException; + method @NonNull public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException; method public int getModifiers(); method @NonNull public String getName(); method @Nullable public Package getPackage(); method @Nullable public java.security.ProtectionDomain getProtectionDomain(); method @Nullable public java.net.URL getResource(@NonNull String); method @Nullable public java.io.InputStream getResourceAsStream(@NonNull String); - method public Object[] getSigners(); + method @Nullable public Object[] getSigners(); method @NonNull public String getSimpleName(); method @Nullable public Class<? super T> getSuperclass(); - method public java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters(); + method @NonNull public java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters(); method public boolean isAnnotation(); method public boolean isAnonymousClass(); method public boolean isArray(); @@ -57941,8 +57974,8 @@ package java.lang { method @NonNull public static String copyValueOf(char[]); method public boolean endsWith(@NonNull String); method public boolean equalsIgnoreCase(@Nullable String); - method @NonNull public static String format(@NonNull String, java.lang.Object...); - method @NonNull public static String format(@NonNull java.util.Locale, @NonNull String, java.lang.Object...); + method @NonNull public static String format(@NonNull String, @NonNull java.lang.Object...); + method @NonNull public static String format(@NonNull java.util.Locale, @NonNull String, @NonNull java.lang.Object...); method @Deprecated public void getBytes(int, int, byte[], int); method public byte[] getBytes(@NonNull String) throws java.io.UnsupportedEncodingException; method public byte[] getBytes(@NonNull java.nio.charset.Charset); @@ -57954,7 +57987,7 @@ package java.lang { method public int indexOf(@NonNull String, int); method @NonNull public String intern(); method public boolean isEmpty(); - method @NonNull public static String join(@NonNull CharSequence, java.lang.CharSequence...); + method @NonNull public static String join(@NonNull CharSequence, @Nullable java.lang.CharSequence...); method @NonNull public static String join(@NonNull CharSequence, @NonNull Iterable<? extends java.lang.CharSequence>); method public int lastIndexOf(int); method public int lastIndexOf(int, int); @@ -57969,8 +58002,8 @@ package java.lang { method @NonNull public String replace(@NonNull CharSequence, @NonNull CharSequence); method @NonNull public String replaceAll(@NonNull String, @NonNull String); method @NonNull public String replaceFirst(@NonNull String, @NonNull String); - method public String[] split(@NonNull String, int); - method public String[] split(@NonNull String); + method @NonNull public String[] split(@NonNull String, int); + method @NonNull public String[] split(@NonNull String); method public boolean startsWith(@NonNull String, int); method public boolean startsWith(@NonNull String); method @NonNull public CharSequence subSequence(int, int); @@ -58171,7 +58204,7 @@ package java.lang { method public long getId(); method @NonNull public final String getName(); method public final int getPriority(); - method public StackTraceElement[] getStackTrace(); + method @NonNull public StackTraceElement[] getStackTrace(); method @NonNull public java.lang.Thread.State getState(); method @Nullable public final ThreadGroup getThreadGroup(); method @Nullable public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler(); @@ -58269,13 +58302,13 @@ package java.lang { method @Nullable public Throwable getCause(); method @Nullable public String getLocalizedMessage(); method @Nullable public String getMessage(); - method public StackTraceElement[] getStackTrace(); - method public final Throwable[] getSuppressed(); + method @NonNull public StackTraceElement[] getStackTrace(); + method @NonNull public final Throwable[] getSuppressed(); method @NonNull public Throwable initCause(@Nullable Throwable); method public void printStackTrace(); method public void printStackTrace(@NonNull java.io.PrintStream); method public void printStackTrace(@NonNull java.io.PrintWriter); - method public void setStackTrace(StackTraceElement[]); + method public void setStackTrace(@NonNull StackTraceElement[]); } public class TypeNotPresentException extends java.lang.RuntimeException { @@ -58598,8 +58631,8 @@ package java.lang.reflect { public class AccessibleObject implements java.lang.reflect.AnnotatedElement { ctor protected AccessibleObject(); method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public boolean isAccessible(); method public static void setAccessible(java.lang.reflect.AccessibleObject[], boolean) throws java.lang.SecurityException; method public void setAccessible(boolean) throws java.lang.SecurityException; @@ -58607,10 +58640,10 @@ package java.lang.reflect { public interface AnnotatedElement { method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>); - method public java.lang.annotation.Annotation[] getAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getAnnotations(); method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@NonNull Class<T>); method @Nullable public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@NonNull Class<T>); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@NonNull Class<T>); method public default boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>); } @@ -58645,20 +58678,20 @@ package java.lang.reflect { method public int getModifiers(); method @NonNull public String getName(); method public java.lang.annotation.Annotation[][] getParameterAnnotations(); - method public Class<?>[] getParameterTypes(); + method @NonNull public Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); method @NonNull public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; method @NonNull public String toGenericString(); } public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { - method public abstract Class<?>[] getExceptionTypes(); - method public java.lang.reflect.Type[] getGenericExceptionTypes(); - method public java.lang.reflect.Type[] getGenericParameterTypes(); - method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations(); + method @NonNull public abstract Class<?>[] getExceptionTypes(); + method @NonNull public java.lang.reflect.Type[] getGenericExceptionTypes(); + method @NonNull public java.lang.reflect.Type[] getGenericParameterTypes(); + method @NonNull public abstract java.lang.annotation.Annotation[][] getParameterAnnotations(); method public int getParameterCount(); - method public abstract Class<?>[] getParameterTypes(); - method public java.lang.reflect.Parameter[] getParameters(); + method @NonNull public abstract Class<?>[] getParameterTypes(); + method @NonNull public java.lang.reflect.Parameter[] getParameters(); method public final boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); @@ -58747,7 +58780,7 @@ package java.lang.reflect { method @NonNull public Class<?>[] getParameterTypes(); method @NonNull public Class<?> getReturnType(); method @NonNull public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); - method @Nullable public Object invoke(@Nullable Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; + method @Nullable public Object invoke(@Nullable Object, @Nullable java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; method public boolean isBridge(); method public boolean isDefault(); method @NonNull public String toGenericString(); @@ -58790,8 +58823,8 @@ package java.lang.reflect { public final class Parameter implements java.lang.reflect.AnnotatedElement { method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getAnnotations(); + method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method @NonNull public java.lang.reflect.Executable getDeclaringExecutable(); method public int getModifiers(); method @NonNull public String getName(); @@ -58804,7 +58837,7 @@ package java.lang.reflect { } public interface ParameterizedType extends java.lang.reflect.Type { - method public java.lang.reflect.Type[] getActualTypeArguments(); + method @NonNull public java.lang.reflect.Type[] getActualTypeArguments(); method @Nullable public java.lang.reflect.Type getOwnerType(); method @NonNull public java.lang.reflect.Type getRawType(); } @@ -58812,9 +58845,9 @@ package java.lang.reflect { public class Proxy implements java.io.Serializable { ctor protected Proxy(@NonNull java.lang.reflect.InvocationHandler); method @NonNull public static java.lang.reflect.InvocationHandler getInvocationHandler(@NonNull Object) throws java.lang.IllegalArgumentException; - method @NonNull public static Class<?> getProxyClass(@Nullable ClassLoader, Class<?>...) throws java.lang.IllegalArgumentException; + method @NonNull public static Class<?> getProxyClass(@Nullable ClassLoader, @NonNull Class<?>...) throws java.lang.IllegalArgumentException; method public static boolean isProxyClass(@NonNull Class<?>); - method @NonNull public static Object newProxyInstance(@Nullable ClassLoader, Class<?>[], @NonNull java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException; + method @NonNull public static Object newProxyInstance(@Nullable ClassLoader, @NonNull Class<?>[], @NonNull java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException; field protected java.lang.reflect.InvocationHandler h; } @@ -58828,7 +58861,7 @@ package java.lang.reflect { } public interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> extends java.lang.reflect.Type { - method public java.lang.reflect.Type[] getBounds(); + method @NonNull public java.lang.reflect.Type[] getBounds(); method @NonNull public D getGenericDeclaration(); method @NonNull public String getName(); } @@ -58840,8 +58873,8 @@ package java.lang.reflect { } public interface WildcardType extends java.lang.reflect.Type { - method public java.lang.reflect.Type[] getLowerBounds(); - method public java.lang.reflect.Type[] getUpperBounds(); + method @NonNull public java.lang.reflect.Type[] getLowerBounds(); + method @NonNull public java.lang.reflect.Type[] getUpperBounds(); } } @@ -59858,20 +59891,20 @@ package java.nio { method public abstract Object array(); method public abstract int arrayOffset(); method public final int capacity(); - method public final java.nio.Buffer clear(); - method public final java.nio.Buffer flip(); + method public java.nio.Buffer clear(); + method public java.nio.Buffer flip(); method public abstract boolean hasArray(); method public final boolean hasRemaining(); method public abstract boolean isDirect(); method public abstract boolean isReadOnly(); method public final int limit(); - method public final java.nio.Buffer limit(int); - method public final java.nio.Buffer mark(); + method public java.nio.Buffer limit(int); + method public java.nio.Buffer mark(); method public final int position(); - method public final java.nio.Buffer position(int); + method public java.nio.Buffer position(int); method public final int remaining(); - method public final java.nio.Buffer reset(); - method public final java.nio.Buffer rewind(); + method public java.nio.Buffer reset(); + method public java.nio.Buffer rewind(); } public class BufferOverflowException extends java.lang.RuntimeException { @@ -59885,7 +59918,7 @@ package java.nio { public abstract class ByteBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.ByteBuffer> { method @NonNull public static java.nio.ByteBuffer allocate(int); method @NonNull public static java.nio.ByteBuffer allocateDirect(int); - method public final byte[] array(); + method @NonNull public final byte[] array(); method public final int arrayOffset(); method @NonNull public abstract java.nio.CharBuffer asCharBuffer(); method @NonNull public abstract java.nio.DoubleBuffer asDoubleBuffer(); @@ -59899,8 +59932,8 @@ package java.nio { method @NonNull public abstract java.nio.ByteBuffer duplicate(); method public abstract byte get(); method public abstract byte get(int); - method @NonNull public java.nio.ByteBuffer get(byte[], int, int); - method @NonNull public java.nio.ByteBuffer get(byte[]); + method @NonNull public java.nio.ByteBuffer get(@NonNull byte[], int, int); + method @NonNull public java.nio.ByteBuffer get(@NonNull byte[]); method public abstract char getChar(); method public abstract char getChar(int); method public abstract double getDouble(); @@ -59919,8 +59952,8 @@ package java.nio { method @NonNull public abstract java.nio.ByteBuffer put(byte); method @NonNull public abstract java.nio.ByteBuffer put(int, byte); method @NonNull public java.nio.ByteBuffer put(@NonNull java.nio.ByteBuffer); - method @NonNull public java.nio.ByteBuffer put(byte[], int, int); - method @NonNull public final java.nio.ByteBuffer put(byte[]); + method @NonNull public java.nio.ByteBuffer put(@NonNull byte[], int, int); + method @NonNull public final java.nio.ByteBuffer put(@NonNull byte[]); method @NonNull public abstract java.nio.ByteBuffer putChar(char); method @NonNull public abstract java.nio.ByteBuffer putChar(int, char); method @NonNull public abstract java.nio.ByteBuffer putDouble(double); @@ -59934,8 +59967,8 @@ package java.nio { method @NonNull public abstract java.nio.ByteBuffer putShort(short); method @NonNull public abstract java.nio.ByteBuffer putShort(int, short); method @NonNull public abstract java.nio.ByteBuffer slice(); - method @NonNull public static java.nio.ByteBuffer wrap(byte[], int, int); - method @NonNull public static java.nio.ByteBuffer wrap(byte[]); + method @NonNull public static java.nio.ByteBuffer wrap(@NonNull byte[], int, int); + method @NonNull public static java.nio.ByteBuffer wrap(@NonNull byte[]); } public final class ByteOrder { @@ -61768,20 +61801,20 @@ package java.security { public abstract class MessageDigest extends java.security.MessageDigestSpi { ctor protected MessageDigest(@NonNull String); - method public byte[] digest(); - method public int digest(byte[], int, int) throws java.security.DigestException; - method public byte[] digest(byte[]); + method @NonNull public byte[] digest(); + method public int digest(@NonNull byte[], int, int) throws java.security.DigestException; + method @NonNull public byte[] digest(@NonNull byte[]); method @NonNull public final String getAlgorithm(); method public final int getDigestLength(); method @NonNull public static java.security.MessageDigest getInstance(@NonNull String) throws java.security.NoSuchAlgorithmException; method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException; method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull java.security.Provider) throws java.security.NoSuchAlgorithmException; method @NonNull public final java.security.Provider getProvider(); - method public static boolean isEqual(byte[], byte[]); + method public static boolean isEqual(@Nullable byte[], @Nullable byte[]); method public void reset(); method public void update(byte); - method public void update(byte[], int, int); - method public void update(byte[]); + method public void update(@NonNull byte[], int, int); + method public void update(@NonNull byte[]); method public final void update(@NonNull java.nio.ByteBuffer); } @@ -64388,7 +64421,7 @@ package java.text { method @NonNull public final StringBuffer format(@NonNull Object, @NonNull StringBuffer, @NonNull java.text.FieldPosition); method @NonNull public abstract StringBuffer format(@NonNull java.util.Date, @NonNull StringBuffer, @NonNull java.text.FieldPosition); method @NonNull public final String format(@NonNull java.util.Date); - method public static java.util.Locale[] getAvailableLocales(); + method @NonNull public static java.util.Locale[] getAvailableLocales(); method @NonNull public java.util.Calendar getCalendar(); method @NonNull public static final java.text.DateFormat getDateInstance(); method @NonNull public static final java.text.DateFormat getDateInstance(int); @@ -64628,7 +64661,7 @@ package java.text { method @NonNull public final String format(long); method @NonNull public abstract StringBuffer format(double, @NonNull StringBuffer, @NonNull java.text.FieldPosition); method @NonNull public abstract StringBuffer format(long, @NonNull StringBuffer, @NonNull java.text.FieldPosition); - method public static java.util.Locale[] getAvailableLocales(); + method @NonNull public static java.util.Locale[] getAvailableLocales(); method @Nullable public java.util.Currency getCurrency(); method @NonNull public static final java.text.NumberFormat getCurrencyInstance(); method @NonNull public static java.text.NumberFormat getCurrencyInstance(@NonNull java.util.Locale); @@ -66282,8 +66315,8 @@ package java.util { method public boolean remove(@Nullable Object); method public boolean removeAll(@NonNull java.util.Collection<?>); method public boolean retainAll(@NonNull java.util.Collection<?>); - method public Object[] toArray(); - method public <T> T[] toArray(T[]); + method @NonNull public Object[] toArray(); + method @NonNull public <T> T[] toArray(@NonNull T[]); } public abstract class AbstractList<E> extends java.util.AbstractCollection<E> implements java.util.List<E> { @@ -66392,161 +66425,161 @@ package java.util { } public class Arrays { - method @NonNull @java.lang.SafeVarargs public static <T> java.util.List<T> asList(T...); - method public static int binarySearch(long[], long); - method public static int binarySearch(long[], int, int, long); - method public static int binarySearch(int[], int); - method public static int binarySearch(int[], int, int, int); - method public static int binarySearch(short[], short); - method public static int binarySearch(short[], int, int, short); - method public static int binarySearch(char[], char); - method public static int binarySearch(char[], int, int, char); - method public static int binarySearch(byte[], byte); - method public static int binarySearch(byte[], int, int, byte); - method public static int binarySearch(double[], double); - method public static int binarySearch(double[], int, int, double); - method public static int binarySearch(float[], float); - method public static int binarySearch(float[], int, int, float); - method public static int binarySearch(Object[], @NonNull Object); - method public static int binarySearch(Object[], int, int, @NonNull Object); - method public static <T> int binarySearch(T[], T, @Nullable java.util.Comparator<? super T>); - method public static <T> int binarySearch(T[], int, int, T, @Nullable java.util.Comparator<? super T>); - method public static <T> T[] copyOf(T[], int); - method public static <T, U> T[] copyOf(U[], int, @NonNull Class<? extends T[]>); - method public static byte[] copyOf(byte[], int); - method public static short[] copyOf(short[], int); - method public static int[] copyOf(int[], int); - method public static long[] copyOf(long[], int); - method public static char[] copyOf(char[], int); - method public static float[] copyOf(float[], int); - method public static double[] copyOf(double[], int); - method public static boolean[] copyOf(boolean[], int); - method public static <T> T[] copyOfRange(T[], int, int); - method public static <T, U> T[] copyOfRange(U[], int, int, @NonNull Class<? extends T[]>); - method public static byte[] copyOfRange(byte[], int, int); - method public static short[] copyOfRange(short[], int, int); - method public static int[] copyOfRange(int[], int, int); - method public static long[] copyOfRange(long[], int, int); - method public static char[] copyOfRange(char[], int, int); - method public static float[] copyOfRange(float[], int, int); - method public static double[] copyOfRange(double[], int, int); - method public static boolean[] copyOfRange(boolean[], int, int); - method public static boolean deepEquals(Object[], Object[]); - method public static int deepHashCode(Object[]); - method @NonNull public static String deepToString(Object[]); - method public static boolean equals(long[], long[]); - method public static boolean equals(int[], int[]); - method public static boolean equals(short[], short[]); - method public static boolean equals(char[], char[]); - method public static boolean equals(byte[], byte[]); - method public static boolean equals(boolean[], boolean[]); - method public static boolean equals(double[], double[]); - method public static boolean equals(float[], float[]); - method public static boolean equals(Object[], Object[]); - method public static void fill(long[], long); - method public static void fill(long[], int, int, long); - method public static void fill(int[], int); - method public static void fill(int[], int, int, int); - method public static void fill(short[], short); - method public static void fill(short[], int, int, short); - method public static void fill(char[], char); - method public static void fill(char[], int, int, char); - method public static void fill(byte[], byte); - method public static void fill(byte[], int, int, byte); - method public static void fill(boolean[], boolean); - method public static void fill(boolean[], int, int, boolean); - method public static void fill(double[], double); - method public static void fill(double[], int, int, double); - method public static void fill(float[], float); - method public static void fill(float[], int, int, float); - method public static void fill(Object[], @Nullable Object); - method public static void fill(Object[], int, int, @Nullable Object); - method public static int hashCode(long[]); - method public static int hashCode(int[]); - method public static int hashCode(short[]); - method public static int hashCode(char[]); - method public static int hashCode(byte[]); - method public static int hashCode(boolean[]); - method public static int hashCode(float[]); - method public static int hashCode(double[]); - method public static int hashCode(Object[]); - method public static <T> void parallelPrefix(T[], @NonNull java.util.function.BinaryOperator<T>); - method public static <T> void parallelPrefix(T[], int, int, @NonNull java.util.function.BinaryOperator<T>); - method public static void parallelPrefix(long[], @NonNull java.util.function.LongBinaryOperator); - method public static void parallelPrefix(long[], int, int, @NonNull java.util.function.LongBinaryOperator); - method public static void parallelPrefix(double[], @NonNull java.util.function.DoubleBinaryOperator); - method public static void parallelPrefix(double[], int, int, @NonNull java.util.function.DoubleBinaryOperator); - method public static void parallelPrefix(int[], @NonNull java.util.function.IntBinaryOperator); - method public static void parallelPrefix(int[], int, int, @NonNull java.util.function.IntBinaryOperator); - method public static <T> void parallelSetAll(T[], @NonNull java.util.function.IntFunction<? extends T>); - method public static void parallelSetAll(int[], @NonNull java.util.function.IntUnaryOperator); - method public static void parallelSetAll(long[], @NonNull java.util.function.IntToLongFunction); - method public static void parallelSetAll(double[], @NonNull java.util.function.IntToDoubleFunction); - method public static void parallelSort(byte[]); - method public static void parallelSort(byte[], int, int); - method public static void parallelSort(char[]); - method public static void parallelSort(char[], int, int); - method public static void parallelSort(short[]); - method public static void parallelSort(short[], int, int); - method public static void parallelSort(int[]); - method public static void parallelSort(int[], int, int); - method public static void parallelSort(long[]); - method public static void parallelSort(long[], int, int); - method public static void parallelSort(float[]); - method public static void parallelSort(float[], int, int); - method public static void parallelSort(double[]); - method public static void parallelSort(double[], int, int); - method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]); - method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int); - method public static <T> void parallelSort(T[], @Nullable java.util.Comparator<? super T>); - method public static <T> void parallelSort(T[], int, int, @Nullable java.util.Comparator<? super T>); - method public static <T> void setAll(T[], @NonNull java.util.function.IntFunction<? extends T>); - method public static void setAll(int[], @NonNull java.util.function.IntUnaryOperator); - method public static void setAll(long[], @NonNull java.util.function.IntToLongFunction); - method public static void setAll(double[], @NonNull java.util.function.IntToDoubleFunction); - method public static void sort(int[]); - method public static void sort(int[], int, int); - method public static void sort(long[]); - method public static void sort(long[], int, int); - method public static void sort(short[]); - method public static void sort(short[], int, int); - method public static void sort(char[]); - method public static void sort(char[], int, int); - method public static void sort(byte[]); - method public static void sort(byte[], int, int); - method public static void sort(float[]); - method public static void sort(float[], int, int); - method public static void sort(double[]); - method public static void sort(double[], int, int); - method public static void sort(Object[]); - method public static void sort(Object[], int, int); - method public static <T> void sort(T[], @Nullable java.util.Comparator<? super T>); - method public static <T> void sort(T[], int, int, @Nullable java.util.Comparator<? super T>); - method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[]); - method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[], int, int); - method @NonNull public static java.util.Spliterator.OfInt spliterator(int[]); - method @NonNull public static java.util.Spliterator.OfInt spliterator(int[], int, int); - method @NonNull public static java.util.Spliterator.OfLong spliterator(long[]); - method @NonNull public static java.util.Spliterator.OfLong spliterator(long[], int, int); - method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[]); - method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[], int, int); - method @NonNull public static <T> java.util.stream.Stream<T> stream(T[]); - method @NonNull public static <T> java.util.stream.Stream<T> stream(T[], int, int); - method @NonNull public static java.util.stream.IntStream stream(int[]); - method @NonNull public static java.util.stream.IntStream stream(int[], int, int); - method @NonNull public static java.util.stream.LongStream stream(long[]); - method @NonNull public static java.util.stream.LongStream stream(long[], int, int); - method @NonNull public static java.util.stream.DoubleStream stream(double[]); - method @NonNull public static java.util.stream.DoubleStream stream(double[], int, int); - method @NonNull public static String toString(long[]); - method @NonNull public static String toString(int[]); - method @NonNull public static String toString(short[]); - method @NonNull public static String toString(char[]); - method @NonNull public static String toString(byte[]); - method @NonNull public static String toString(boolean[]); - method @NonNull public static String toString(float[]); - method @NonNull public static String toString(double[]); - method @NonNull public static String toString(Object[]); + method @NonNull @java.lang.SafeVarargs public static <T> java.util.List<T> asList(@NonNull T...); + method public static int binarySearch(@NonNull long[], long); + method public static int binarySearch(@NonNull long[], int, int, long); + method public static int binarySearch(@NonNull int[], int); + method public static int binarySearch(@NonNull int[], int, int, int); + method public static int binarySearch(@NonNull short[], short); + method public static int binarySearch(@NonNull short[], int, int, short); + method public static int binarySearch(@NonNull char[], char); + method public static int binarySearch(@NonNull char[], int, int, char); + method public static int binarySearch(@NonNull byte[], byte); + method public static int binarySearch(@NonNull byte[], int, int, byte); + method public static int binarySearch(@NonNull double[], double); + method public static int binarySearch(@NonNull double[], int, int, double); + method public static int binarySearch(@NonNull float[], float); + method public static int binarySearch(@NonNull float[], int, int, float); + method public static int binarySearch(@NonNull Object[], @NonNull Object); + method public static int binarySearch(@NonNull Object[], int, int, @NonNull Object); + method public static <T> int binarySearch(@NonNull T[], T, @Nullable java.util.Comparator<? super T>); + method public static <T> int binarySearch(@NonNull T[], int, int, T, @Nullable java.util.Comparator<? super T>); + method @NonNull public static <T> T[] copyOf(@NonNull T[], int); + method @NonNull public static <T, U> T[] copyOf(@NonNull U[], int, @NonNull Class<? extends T[]>); + method @NonNull public static byte[] copyOf(@NonNull byte[], int); + method @NonNull public static short[] copyOf(@NonNull short[], int); + method @NonNull public static int[] copyOf(@NonNull int[], int); + method @NonNull public static long[] copyOf(@NonNull long[], int); + method @NonNull public static char[] copyOf(@NonNull char[], int); + method @NonNull public static float[] copyOf(@NonNull float[], int); + method @NonNull public static double[] copyOf(@NonNull double[], int); + method @NonNull public static boolean[] copyOf(@NonNull boolean[], int); + method @NonNull public static <T> T[] copyOfRange(@NonNull T[], int, int); + method @NonNull public static <T, U> T[] copyOfRange(@NonNull U[], int, int, @NonNull Class<? extends T[]>); + method @NonNull public static byte[] copyOfRange(@NonNull byte[], int, int); + method @NonNull public static short[] copyOfRange(@NonNull short[], int, int); + method @NonNull public static int[] copyOfRange(@NonNull int[], int, int); + method @NonNull public static long[] copyOfRange(@NonNull long[], int, int); + method @NonNull public static char[] copyOfRange(@NonNull char[], int, int); + method @NonNull public static float[] copyOfRange(@NonNull float[], int, int); + method @NonNull public static double[] copyOfRange(@NonNull double[], int, int); + method @NonNull public static boolean[] copyOfRange(@NonNull boolean[], int, int); + method public static boolean deepEquals(@Nullable Object[], @Nullable Object[]); + method public static int deepHashCode(@Nullable Object[]); + method @NonNull public static String deepToString(@Nullable Object[]); + method public static boolean equals(@Nullable long[], @Nullable long[]); + method public static boolean equals(@Nullable int[], @Nullable int[]); + method public static boolean equals(@Nullable short[], @Nullable short[]); + method public static boolean equals(@Nullable char[], @Nullable char[]); + method public static boolean equals(@Nullable byte[], @Nullable byte[]); + method public static boolean equals(@Nullable boolean[], @Nullable boolean[]); + method public static boolean equals(@Nullable double[], @Nullable double[]); + method public static boolean equals(@Nullable float[], @Nullable float[]); + method public static boolean equals(@Nullable Object[], @Nullable Object[]); + method public static void fill(@NonNull long[], long); + method public static void fill(@NonNull long[], int, int, long); + method public static void fill(@NonNull int[], int); + method public static void fill(@NonNull int[], int, int, int); + method public static void fill(@NonNull short[], short); + method public static void fill(@NonNull short[], int, int, short); + method public static void fill(@NonNull char[], char); + method public static void fill(@NonNull char[], int, int, char); + method public static void fill(@NonNull byte[], byte); + method public static void fill(@NonNull byte[], int, int, byte); + method public static void fill(@NonNull boolean[], boolean); + method public static void fill(@NonNull boolean[], int, int, boolean); + method public static void fill(@NonNull double[], double); + method public static void fill(@NonNull double[], int, int, double); + method public static void fill(@NonNull float[], float); + method public static void fill(@NonNull float[], int, int, float); + method public static void fill(@NonNull Object[], @Nullable Object); + method public static void fill(@NonNull Object[], int, int, @Nullable Object); + method public static int hashCode(@Nullable long[]); + method public static int hashCode(@Nullable int[]); + method public static int hashCode(@Nullable short[]); + method public static int hashCode(@Nullable char[]); + method public static int hashCode(@Nullable byte[]); + method public static int hashCode(@Nullable boolean[]); + method public static int hashCode(@Nullable float[]); + method public static int hashCode(@Nullable double[]); + method public static int hashCode(@Nullable Object[]); + method public static <T> void parallelPrefix(@NonNull T[], @NonNull java.util.function.BinaryOperator<T>); + method public static <T> void parallelPrefix(@NonNull T[], int, int, @NonNull java.util.function.BinaryOperator<T>); + method public static void parallelPrefix(@NonNull long[], @NonNull java.util.function.LongBinaryOperator); + method public static void parallelPrefix(@NonNull long[], int, int, @NonNull java.util.function.LongBinaryOperator); + method public static void parallelPrefix(@NonNull double[], @NonNull java.util.function.DoubleBinaryOperator); + method public static void parallelPrefix(@NonNull double[], int, int, @NonNull java.util.function.DoubleBinaryOperator); + method public static void parallelPrefix(@NonNull int[], @NonNull java.util.function.IntBinaryOperator); + method public static void parallelPrefix(@NonNull int[], int, int, @NonNull java.util.function.IntBinaryOperator); + method public static <T> void parallelSetAll(@NonNull T[], @NonNull java.util.function.IntFunction<? extends T>); + method public static void parallelSetAll(@NonNull int[], @NonNull java.util.function.IntUnaryOperator); + method public static void parallelSetAll(@NonNull long[], @NonNull java.util.function.IntToLongFunction); + method public static void parallelSetAll(@NonNull double[], @NonNull java.util.function.IntToDoubleFunction); + method public static void parallelSort(@NonNull byte[]); + method public static void parallelSort(@NonNull byte[], int, int); + method public static void parallelSort(@NonNull char[]); + method public static void parallelSort(@NonNull char[], int, int); + method public static void parallelSort(@NonNull short[]); + method public static void parallelSort(@NonNull short[], int, int); + method public static void parallelSort(@NonNull int[]); + method public static void parallelSort(@NonNull int[], int, int); + method public static void parallelSort(@NonNull long[]); + method public static void parallelSort(@NonNull long[], int, int); + method public static void parallelSort(@NonNull float[]); + method public static void parallelSort(@NonNull float[], int, int); + method public static void parallelSort(@NonNull double[]); + method public static void parallelSort(@NonNull double[], int, int); + method public static <T extends java.lang.Comparable<? super T>> void parallelSort(@NonNull T[]); + method public static <T extends java.lang.Comparable<? super T>> void parallelSort(@NonNull T[], int, int); + method public static <T> void parallelSort(@NonNull T[], @Nullable java.util.Comparator<? super T>); + method public static <T> void parallelSort(@NonNull T[], int, int, @Nullable java.util.Comparator<? super T>); + method public static <T> void setAll(@NonNull T[], @NonNull java.util.function.IntFunction<? extends T>); + method public static void setAll(@NonNull int[], @NonNull java.util.function.IntUnaryOperator); + method public static void setAll(@NonNull long[], @NonNull java.util.function.IntToLongFunction); + method public static void setAll(@NonNull double[], @NonNull java.util.function.IntToDoubleFunction); + method public static void sort(@NonNull int[]); + method public static void sort(@NonNull int[], int, int); + method public static void sort(@NonNull long[]); + method public static void sort(@NonNull long[], int, int); + method public static void sort(@NonNull short[]); + method public static void sort(@NonNull short[], int, int); + method public static void sort(@NonNull char[]); + method public static void sort(@NonNull char[], int, int); + method public static void sort(@NonNull byte[]); + method public static void sort(@NonNull byte[], int, int); + method public static void sort(@NonNull float[]); + method public static void sort(@NonNull float[], int, int); + method public static void sort(@NonNull double[]); + method public static void sort(@NonNull double[], int, int); + method public static void sort(@NonNull Object[]); + method public static void sort(@NonNull Object[], int, int); + method public static <T> void sort(@NonNull T[], @Nullable java.util.Comparator<? super T>); + method public static <T> void sort(@NonNull T[], int, int, @Nullable java.util.Comparator<? super T>); + method @NonNull public static <T> java.util.Spliterator<T> spliterator(@NonNull T[]); + method @NonNull public static <T> java.util.Spliterator<T> spliterator(@NonNull T[], int, int); + method @NonNull public static java.util.Spliterator.OfInt spliterator(@NonNull int[]); + method @NonNull public static java.util.Spliterator.OfInt spliterator(@NonNull int[], int, int); + method @NonNull public static java.util.Spliterator.OfLong spliterator(@NonNull long[]); + method @NonNull public static java.util.Spliterator.OfLong spliterator(@NonNull long[], int, int); + method @NonNull public static java.util.Spliterator.OfDouble spliterator(@NonNull double[]); + method @NonNull public static java.util.Spliterator.OfDouble spliterator(@NonNull double[], int, int); + method @NonNull public static <T> java.util.stream.Stream<T> stream(@NonNull T[]); + method @NonNull public static <T> java.util.stream.Stream<T> stream(@NonNull T[], int, int); + method @NonNull public static java.util.stream.IntStream stream(@NonNull int[]); + method @NonNull public static java.util.stream.IntStream stream(@NonNull int[], int, int); + method @NonNull public static java.util.stream.LongStream stream(@NonNull long[]); + method @NonNull public static java.util.stream.LongStream stream(@NonNull long[], int, int); + method @NonNull public static java.util.stream.DoubleStream stream(@NonNull double[]); + method @NonNull public static java.util.stream.DoubleStream stream(@NonNull double[], int, int); + method @NonNull public static String toString(@Nullable long[]); + method @NonNull public static String toString(@Nullable int[]); + method @NonNull public static String toString(@Nullable short[]); + method @NonNull public static String toString(@Nullable char[]); + method @NonNull public static String toString(@Nullable byte[]); + method @NonNull public static String toString(@Nullable boolean[]); + method @NonNull public static String toString(@Nullable float[]); + method @NonNull public static String toString(@Nullable double[]); + method @NonNull public static String toString(@Nullable Object[]); } public class Base64 { @@ -66630,7 +66663,7 @@ package java.util { method public int getActualMaximum(int); method public int getActualMinimum(int); method @NonNull public static java.util.Set<java.lang.String> getAvailableCalendarTypes(); - method public static java.util.Locale[] getAvailableLocales(); + method @NonNull public static java.util.Locale[] getAvailableLocales(); method @NonNull public String getCalendarType(); method @Nullable public String getDisplayName(int, int, @NonNull java.util.Locale); method @Nullable public java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, @NonNull java.util.Locale); @@ -66718,8 +66751,8 @@ package java.util { field public static final int YEAR = 1; // 0x1 field public static final int ZONE_OFFSET = 15; // 0xf field protected boolean areFieldsSet; - field protected int[] fields; - field protected boolean[] isSet; + field @NonNull protected int[] fields; + field @NonNull protected boolean[] isSet; field protected boolean isTimeSet; field protected long time; } @@ -66730,7 +66763,7 @@ package java.util { method @NonNull public java.util.Calendar.Builder set(int, int); method @NonNull public java.util.Calendar.Builder setCalendarType(@NonNull String); method @NonNull public java.util.Calendar.Builder setDate(int, int, int); - method @NonNull public java.util.Calendar.Builder setFields(int...); + method @NonNull public java.util.Calendar.Builder setFields(@NonNull int...); method @NonNull public java.util.Calendar.Builder setInstant(long); method @NonNull public java.util.Calendar.Builder setInstant(@NonNull java.util.Date); method @NonNull public java.util.Calendar.Builder setLenient(boolean); @@ -66760,12 +66793,12 @@ package java.util { method public int size(); method @NonNull public default java.util.Spliterator<E> spliterator(); method @NonNull public default java.util.stream.Stream<E> stream(); - method public Object[] toArray(); - method public <T> T[] toArray(T[]); + method @NonNull public Object[] toArray(); + method @NonNull public <T> T[] toArray(@NonNull T[]); } public class Collections { - method @java.lang.SafeVarargs public static <T> boolean addAll(@NonNull java.util.Collection<? super T>, T...); + method @java.lang.SafeVarargs public static <T> boolean addAll(@NonNull java.util.Collection<? super T>, @NonNull T...); method @NonNull public static <T> java.util.Queue<T> asLifoQueue(@NonNull java.util.Deque<T>); method public static <T> int binarySearch(@NonNull java.util.List<? extends java.lang.Comparable<? super T>>, @NonNull T); method public static <T> int binarySearch(@NonNull java.util.List<? extends T>, T, @Nullable java.util.Comparator<? super T>); @@ -67283,7 +67316,7 @@ package java.util { method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>, @NonNull java.util.Locale.FilteringMode); method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>); method @NonNull public static java.util.Locale forLanguageTag(@NonNull String); - method public static java.util.Locale[] getAvailableLocales(); + method @NonNull public static java.util.Locale[] getAvailableLocales(); method @NonNull public String getCountry(); method @NonNull public static java.util.Locale getDefault(); method @NonNull public static java.util.Locale getDefault(@NonNull java.util.Locale.Category); @@ -67301,8 +67334,8 @@ package java.util { method @NonNull public java.util.Set<java.lang.Character> getExtensionKeys(); method @NonNull public String getISO3Country() throws java.util.MissingResourceException; method @NonNull public String getISO3Language() throws java.util.MissingResourceException; - method public static String[] getISOCountries(); - method public static String[] getISOLanguages(); + method @NonNull public static String[] getISOCountries(); + method @NonNull public static String[] getISOLanguages(); method @NonNull public String getLanguage(); method @NonNull public String getScript(); method @NonNull public java.util.Set<java.lang.String> getUnicodeLocaleAttributes(); @@ -67496,7 +67529,7 @@ package java.util { method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>); method public static boolean deepEquals(@Nullable Object, @Nullable Object); method public static boolean equals(@Nullable Object, @Nullable Object); - method public static int hash(java.lang.Object...); + method public static int hash(@Nullable java.lang.Object...); method public static int hashCode(@Nullable Object); method public static boolean isNull(@Nullable Object); method public static boolean nonNull(@Nullable Object); @@ -68161,7 +68194,7 @@ package java.util { method public void addElement(E); method public int capacity(); method @NonNull public Object clone(); - method public void copyInto(Object[]); + method public void copyInto(@NonNull Object[]); method public E elementAt(int); method @NonNull public java.util.Enumeration<E> elements(); method public void ensureCapacity(int); @@ -68181,7 +68214,7 @@ package java.util { method public void trimToSize(); field protected int capacityIncrement; field protected int elementCount; - field protected Object[] elementData; + field @NonNull protected Object[] elementData; } public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> { @@ -68572,7 +68605,7 @@ package java.util.concurrent { public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable { ctor public CopyOnWriteArrayList(); ctor public CopyOnWriteArrayList(@NonNull java.util.Collection<? extends E>); - ctor public CopyOnWriteArrayList(E[]); + ctor public CopyOnWriteArrayList(@NonNull E[]); method public boolean add(E); method public void add(int, E); method public boolean addAll(@NonNull java.util.Collection<? extends E>); @@ -68600,8 +68633,8 @@ package java.util.concurrent { method public E set(int, E); method public int size(); method @NonNull public java.util.List<E> subList(int, int); - method public Object[] toArray(); - method public <T> T[] toArray(T[]); + method @NonNull public Object[] toArray(); + method @NonNull public <T> T[] toArray(@NonNull T[]); } public class CopyOnWriteArraySet<E> extends java.util.AbstractSet<E> implements java.io.Serializable { @@ -70353,7 +70386,7 @@ package java.util.logging { method public void config(@NonNull java.util.function.Supplier<java.lang.String>); method public void entering(@Nullable String, @Nullable String); method public void entering(@Nullable String, @Nullable String, @Nullable Object); - method public void entering(@Nullable String, @Nullable String, Object[]); + method public void entering(@Nullable String, @Nullable String, @Nullable Object[]); method public void exiting(@Nullable String, @Nullable String); method public void exiting(@Nullable String, @Nullable String, @Nullable Object); method public void fine(@Nullable String); @@ -70366,7 +70399,7 @@ package java.util.logging { method @NonNull public static java.util.logging.Logger getAnonymousLogger(@Nullable String); method @Nullable public java.util.logging.Filter getFilter(); method @NonNull public static final java.util.logging.Logger getGlobal(); - method public java.util.logging.Handler[] getHandlers(); + method @NonNull public java.util.logging.Handler[] getHandlers(); method @Nullable public java.util.logging.Level getLevel(); method @NonNull public static java.util.logging.Logger getLogger(@NonNull String); method @NonNull public static java.util.logging.Logger getLogger(@NonNull String, @Nullable String); @@ -70382,7 +70415,7 @@ package java.util.logging { method public void log(@NonNull java.util.logging.Level, @Nullable String); method public void log(@NonNull java.util.logging.Level, @NonNull java.util.function.Supplier<java.lang.String>); method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Object); - method public void log(@NonNull java.util.logging.Level, @Nullable String, Object[]); + method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Object[]); method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Throwable); method public void log(@NonNull java.util.logging.Level, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>); method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String); @@ -70393,8 +70426,8 @@ package java.util.logging { method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>); method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String); method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Object); - method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, Object[]); - method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, java.lang.Object...); + method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Object[]); + method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, @Nullable java.lang.Object...); method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable); method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, @Nullable Throwable); method public void removeHandler(@Nullable java.util.logging.Handler) throws java.lang.SecurityException; @@ -70656,8 +70689,8 @@ package java.util.regex { method public static boolean matches(@NonNull String, @NonNull CharSequence); method @NonNull public String pattern(); method @NonNull public static String quote(@NonNull String); - method public String[] split(@NonNull CharSequence, int); - method public String[] split(@NonNull CharSequence); + method @NonNull public String[] split(@NonNull CharSequence, int); + method @NonNull public String[] split(@NonNull CharSequence); method @NonNull public java.util.stream.Stream<java.lang.String> splitAsStream(@NonNull CharSequence); field public static final int CANON_EQ = 128; // 0x80 field public static final int CASE_INSENSITIVE = 2; // 0x2 diff --git a/api/system-current.txt b/api/system-current.txt index 8b007898c839..e17459bf4852 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -101,6 +101,7 @@ package android { field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE"; field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG"; field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT"; + field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD"; field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS"; field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING"; field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION"; @@ -839,6 +840,7 @@ package android.content { field public static final String CONTEXTHUB_SERVICE = "contexthub"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; + field public static final String NETD_SERVICE = "netd"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block"; @@ -3057,6 +3059,7 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { ctor public CaptivePortal(android.os.IBinder); + method public void logEvent(int, String); method public void useNetwork(); field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 @@ -3064,7 +3067,7 @@ package android.net { } public class ConnectivityManager { - method @RequiresPermission("android.permission.PACKET_KEEPALIVE_OFFLOAD") public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); + method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback); method public boolean getAvoidBadWifi(); method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl(); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler); @@ -3096,12 +3099,14 @@ package android.net { public final class IpPrefix implements android.os.Parcelable { ctor public IpPrefix(java.net.InetAddress, int); + ctor public IpPrefix(String); } public class LinkAddress implements android.os.Parcelable { ctor public LinkAddress(java.net.InetAddress, int, int, int); ctor public LinkAddress(java.net.InetAddress, int); ctor public LinkAddress(String); + ctor public LinkAddress(String, int, int); method public boolean isGlobalPreferred(); method public boolean isIPv4(); method public boolean isIPv6(); @@ -3112,6 +3117,7 @@ package android.net { ctor public LinkProperties(); ctor public LinkProperties(android.net.LinkProperties); method public boolean addDnsServer(java.net.InetAddress); + method public boolean addLinkAddress(android.net.LinkAddress); method public boolean addRoute(android.net.RouteInfo); method public void clear(); method @Nullable public android.net.IpPrefix getNat64Prefix(); @@ -3126,6 +3132,7 @@ package android.net { method public boolean isProvisioned(); method public boolean isReachable(java.net.InetAddress); method public boolean removeDnsServer(java.net.InetAddress); + method public boolean removeLinkAddress(android.net.LinkAddress); method public boolean removeRoute(android.net.RouteInfo); method public void setDnsServers(java.util.Collection<java.net.InetAddress>); method public void setDomains(String); @@ -3142,6 +3149,7 @@ package android.net { } public class Network implements android.os.Parcelable { + ctor public Network(android.net.Network); method public android.net.Network getPrivateDnsBypassingCopy(); } @@ -3227,10 +3235,31 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } + public final class StaticIpConfiguration implements android.os.Parcelable { + ctor public StaticIpConfiguration(); + ctor public StaticIpConfiguration(android.net.StaticIpConfiguration); + method public void addDnsServer(java.net.InetAddress); + method public void clear(); + method public int describeContents(); + method public java.util.List<java.net.InetAddress> getDnsServers(); + method public String getDomains(); + method public java.net.InetAddress getGateway(); + method public android.net.LinkAddress getIpAddress(); + method public java.util.List<android.net.RouteInfo> getRoutes(String); + method public void setDomains(String); + method public void setGateway(java.net.InetAddress); + method public void setIpAddress(android.net.LinkAddress); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR; + } + public class TrafficStats { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); method public static void setThreadStatsTagRestore(); + field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40 + field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46 + field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42 } public class VpnService extends android.app.Service { @@ -3252,6 +3281,49 @@ package android.net { } +package android.net.apf { + + public class ApfCapabilities { + ctor public ApfCapabilities(int, int, int); + method public static boolean getApfDrop8023Frames(android.content.Context); + method public static int[] getApfEthTypeBlackList(android.content.Context); + method public boolean hasDataAccess(); + field public final int apfPacketFormat; + field public final int apfVersionSupported; + field public final int maximumApfProgramSize; + } + +} + +package android.net.captiveportal { + + public final class CaptivePortalProbeResult { + ctor public CaptivePortalProbeResult(int); + ctor public CaptivePortalProbeResult(int, String, String); + ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec); + method public boolean isFailed(); + method public boolean isPortal(); + method public boolean isSuccessful(); + field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED; + field public static final int FAILED_CODE = 599; // 0x257 + field public static final int PORTAL_CODE = 302; // 0x12e + field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS; + field public static final int SUCCESS_CODE = 204; // 0xcc + field public final String detectUrl; + field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec; + field public final String redirectUrl; + } + + public abstract class CaptivePortalProbeSpec { + method public String getEncodedSpec(); + method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String); + method public java.net.URL getUrl(); + method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String); + method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String); + } + +} + package android.net.metrics { public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { @@ -3411,10 +3483,19 @@ package android.net.metrics { package android.net.util { public class SocketUtils { + method public static void addArpEntry(java.net.Inet4Address, android.net.MacAddress, String, java.io.FileDescriptor) throws java.io.IOException; + method public static void attachControlPacketFilter(java.io.FileDescriptor, int) throws java.net.SocketException; + method public static void attachDhcpFilter(java.io.FileDescriptor) throws java.net.SocketException; + method public static void attachRaFilter(java.io.FileDescriptor, int) throws java.net.SocketException; + method public static void bindSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException; + method public static void closeSocket(java.io.FileDescriptor) throws java.io.IOException; + method public static void connectSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); method public static java.net.SocketAddress makePacketSocketAddress(short, int); method public static java.net.SocketAddress makePacketSocketAddress(int, byte[]); + method public static void sendTo(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static void setSocketTimeValueOption(java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException; } } @@ -3874,6 +3955,7 @@ package android.nfc { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler); method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setNfcSecure(boolean); field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1 } @@ -3890,6 +3972,36 @@ package android.os { field public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP"; } + public class BugreportManager { + method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport(); + method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + } + + public abstract static class BugreportManager.BugreportCallback { + ctor public BugreportManager.BugreportCallback(); + method public void onError(int); + method public void onFinished(); + method public void onProgress(float); + field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 + field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 + field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 + field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 + } + + public final class BugreportParams { + ctor public BugreportParams(@android.os.BugreportParams.BugreportMode int); + method public int getMode(); + field public static final int BUGREPORT_MODE_FULL = 0; // 0x0 + field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1 + field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2 + field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4 + field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3 + field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5 + } + + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"BUGREPORT_MODE_"}, value={android.os.BugreportParams.BUGREPORT_MODE_FULL, android.os.BugreportParams.BUGREPORT_MODE_INTERACTIVE, android.os.BugreportParams.BUGREPORT_MODE_REMOTE, android.os.BugreportParams.BUGREPORT_MODE_WEAR, android.os.BugreportParams.BUGREPORT_MODE_TELEPHONY, android.os.BugreportParams.BUGREPORT_MODE_WIFI}) public static @interface BugreportParams.BugreportMode { + } + public final class ConfigUpdate { field public static final String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB"; field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS"; @@ -4202,6 +4314,7 @@ package android.os { } public final class UserHandle implements android.os.Parcelable { + method public static int getAppId(int); method public int getIdentifier(); method @Deprecated public boolean isOwner(); method public boolean isSystem(); @@ -5946,8 +6059,9 @@ package android.telephony { } public class PhoneStateListener { - method public void onCallAttributesChanged(android.telephony.CallAttributes); + method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); method public void onCallDisconnectCauseChanged(int, int); + method public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); method public void onPreciseCallStateChanged(android.telephony.PreciseCallState); method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState); method public void onRadioPowerStateChanged(int); @@ -5955,6 +6069,7 @@ package android.telephony { method public void onVoiceActivationStateChanged(int); field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000 + field public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000 field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800 field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000 field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000 @@ -6125,7 +6240,6 @@ package android.telephony { public class SubscriptionInfo implements android.os.Parcelable { method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); - method public int getCardId(); method public int getProfileClass(); } @@ -6185,7 +6299,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); - method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCardIdForDefaultEuicc(); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); @@ -6206,9 +6319,9 @@ package android.telephony { method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); method public int getSimCardState(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getSimLocale(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSupportedRadioAccessFamily(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccCardInfo[] getUiccCardsInfo(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo(); method @Nullable public android.os.Bundle getVisualVoicemailSettings(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState(); @@ -6217,6 +6330,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCurrentPotentialEmergencyNumber(@NonNull String); method public boolean isDataConnectivityPossible(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMultisimCarrierRestricted(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); @@ -6233,6 +6347,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultisimCarrierRestriction(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int); @@ -6256,7 +6371,6 @@ package android.telephony { field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; - field public static final int INVALID_CARD_ID = -1; // 0xffffffff field public static final long MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS = 60000L; // 0xea60L field public static final int NETWORK_MODE_CDMA_EVDO = 4; // 0x4 field public static final int NETWORK_MODE_CDMA_NO_EVDO = 5; // 0x5 @@ -6331,18 +6445,6 @@ package android.telephony { field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR; } - public class UiccCardInfo implements android.os.Parcelable { - ctor public UiccCardInfo(boolean, int, String, String, int); - method public int describeContents(); - method public int getCardId(); - method public String getEid(); - method public String getIccId(); - method public int getSlotIndex(); - method public boolean isEuicc(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR; - } - public class UiccSlotInfo implements android.os.Parcelable { ctor public UiccSlotInfo(boolean, boolean, String, int, int, boolean); method public int describeContents(); @@ -6370,7 +6472,7 @@ package android.telephony { package android.telephony.data { public final class DataCallResponse implements android.os.Parcelable { - ctor public DataCallResponse(int, int, int, int, @Nullable String, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.lang.String>, int); + ctor public DataCallResponse(int, int, int, int, int, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.lang.String>, int); ctor public DataCallResponse(android.os.Parcel); method public int describeContents(); method public int getActive(); @@ -6381,9 +6483,9 @@ package android.telephony.data { method @NonNull public String getIfname(); method public int getMtu(); method @NonNull public java.util.List<java.lang.String> getPcscfs(); + method public int getProtocolType(); method public int getStatus(); method public int getSuggestedRetryTime(); - method @NonNull public String getType(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; } @@ -6397,8 +6499,8 @@ package android.telephony.data { method public int getMtu(); method public String getPassword(); method public int getProfileId(); - method public String getProtocol(); - method public String getRoamingProtocol(); + method public int getProtocol(); + method public int getRoamingProtocol(); method public int getSupportedApnTypesBitmap(); method public int getType(); method public String getUserName(); @@ -6624,11 +6726,13 @@ package android.telephony.ims { method public static int getCallTypeFromVideoState(int); method public int getEmergencyCallRouting(); method public int getEmergencyServiceCategories(); + method public java.util.List<java.lang.String> getEmergencyUrns(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); method public int getRestrictCause(); method public int getServiceType(); method public static int getVideoStateFromCallType(int); method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile); + method public boolean isEmergencyCallTesting(); method public boolean isVideoCall(); method public boolean isVideoPaused(); method public static int presentationToOir(int); @@ -6637,7 +6741,9 @@ package android.telephony.ims { method public void setCallExtraInt(String, int); method public void setCallRestrictCause(int); method public void setEmergencyCallRouting(int); + method public void setEmergencyCallTesting(boolean); method public void setEmergencyServiceCategories(int); + method public void setEmergencyUrns(java.util.List<java.lang.String>); method public void updateCallExtras(android.telephony.ims.ImsCallProfile); method public void updateCallType(android.telephony.ims.ImsCallProfile); method public void updateMediaProfile(android.telephony.ims.ImsCallProfile); diff --git a/api/test-current.txt b/api/test-current.txt index 03692e91cd72..1384f0b7b41e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -600,6 +600,7 @@ package android.net { public class CaptivePortal implements android.os.Parcelable { ctor public CaptivePortal(android.os.IBinder); + method public void logEvent(int, String); method public void useNetwork(); field public static final int APP_RETURN_DISMISSED = 0; // 0x0 field public static final int APP_RETURN_UNWANTED = 1; // 0x1 @@ -613,6 +614,7 @@ package android.net { public final class IpPrefix implements android.os.Parcelable { ctor public IpPrefix(java.net.InetAddress, int); + ctor public IpPrefix(String); } public final class IpSecManager { @@ -621,6 +623,9 @@ package android.net { public class LinkAddress implements android.os.Parcelable { ctor public LinkAddress(java.net.InetAddress, int, int, int); + ctor public LinkAddress(java.net.InetAddress, int); + ctor public LinkAddress(String); + ctor public LinkAddress(String, int, int); method public boolean isGlobalPreferred(); method public boolean isIPv4(); method public boolean isIPv6(); @@ -630,6 +635,7 @@ package android.net { public final class LinkProperties implements android.os.Parcelable { ctor public LinkProperties(android.net.LinkProperties); method public boolean addDnsServer(java.net.InetAddress); + method public boolean addLinkAddress(android.net.LinkAddress); method @Nullable public android.net.IpPrefix getNat64Prefix(); method public java.util.List<java.net.InetAddress> getPcscfServers(); method public String getTcpBufferSizes(); @@ -642,6 +648,7 @@ package android.net { method public boolean isProvisioned(); method public boolean isReachable(java.net.InetAddress); method public boolean removeDnsServer(java.net.InetAddress); + method public boolean removeLinkAddress(android.net.LinkAddress); method public boolean removeRoute(android.net.RouteInfo); method public void setNat64Prefix(android.net.IpPrefix); method public void setPcscfServers(java.util.Collection<java.net.InetAddress>); @@ -652,6 +659,7 @@ package android.net { } public class Network implements android.os.Parcelable { + ctor public Network(android.net.Network); method public android.net.Network getPrivateDnsBypassingCopy(); } @@ -669,11 +677,75 @@ package android.net { field public static final int RTN_UNREACHABLE = 7; // 0x7 } + public final class StaticIpConfiguration implements android.os.Parcelable { + ctor public StaticIpConfiguration(); + ctor public StaticIpConfiguration(android.net.StaticIpConfiguration); + method public void addDnsServer(java.net.InetAddress); + method public void clear(); + method public int describeContents(); + method public java.util.List<java.net.InetAddress> getDnsServers(); + method public String getDomains(); + method public java.net.InetAddress getGateway(); + method public android.net.LinkAddress getIpAddress(); + method public java.util.List<android.net.RouteInfo> getRoutes(String); + method public void setDomains(String); + method public void setGateway(java.net.InetAddress); + method public void setIpAddress(android.net.LinkAddress); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR; + } + public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); method public static long getLoopbackTxBytes(); method public static long getLoopbackTxPackets(); + field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40 + field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46 + field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42 + } + +} + +package android.net.apf { + + public class ApfCapabilities { + ctor public ApfCapabilities(int, int, int); + method public static boolean getApfDrop8023Frames(android.content.Context); + method public static int[] getApfEthTypeBlackList(android.content.Context); + method public boolean hasDataAccess(); + field public final int apfPacketFormat; + field public final int apfVersionSupported; + field public final int maximumApfProgramSize; + } + +} + +package android.net.captiveportal { + + public final class CaptivePortalProbeResult { + ctor public CaptivePortalProbeResult(int); + ctor public CaptivePortalProbeResult(int, String, String); + ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec); + method public boolean isFailed(); + method public boolean isPortal(); + method public boolean isSuccessful(); + field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED; + field public static final int FAILED_CODE = 599; // 0x257 + field public static final int PORTAL_CODE = 302; // 0x12e + field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS; + field public static final int SUCCESS_CODE = 204; // 0xcc + field public final String detectUrl; + field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec; + field public final String redirectUrl; + } + + public abstract class CaptivePortalProbeSpec { + method public String getEncodedSpec(); + method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String); + method public java.net.URL getUrl(); + method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String); + method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String); } } @@ -834,6 +906,26 @@ package android.net.metrics { } +package android.net.util { + + public class SocketUtils { + method public static void addArpEntry(java.net.Inet4Address, android.net.MacAddress, String, java.io.FileDescriptor) throws java.io.IOException; + method public static void attachControlPacketFilter(java.io.FileDescriptor, int) throws java.net.SocketException; + method public static void attachDhcpFilter(java.io.FileDescriptor) throws java.net.SocketException; + method public static void attachRaFilter(java.io.FileDescriptor, int) throws java.net.SocketException; + method public static void bindSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException; + method public static void closeSocket(java.io.FileDescriptor) throws java.io.IOException; + method public static void connectSocket(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int); + method public static java.net.SocketAddress makePacketSocketAddress(short, int); + method public static java.net.SocketAddress makePacketSocketAddress(int, byte[]); + method public static void sendTo(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static void setSocketTimeValueOption(java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException; + } + +} + package android.os { public static class Build.VERSION { @@ -1699,6 +1791,10 @@ package android.view { method public boolean isSystemGroup(); } + public abstract class LayoutInflater { + method public void setPrecompiledLayoutsEnabledForTesting(boolean); + } + public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable { method public void setActionButton(int); method public void setButtonState(int); diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS index 13157505fc28..deebd4e3cd3b 100644 --- a/cmds/statsd/OWNERS +++ b/cmds/statsd/OWNERS @@ -1,6 +1,7 @@ bookatz@google.com cjyu@google.com dwchen@google.com +gaillard@google.com jinyithu@google.com joeo@google.com kwekua@google.com diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 30536099456a..5fd148e5d5af 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -23,9 +23,11 @@ option java_outer_classname = "AtomsProto"; import "frameworks/base/cmds/statsd/src/atom_field_options.proto"; import "frameworks/base/core/proto/android/app/enums.proto"; import "frameworks/base/core/proto/android/app/job/enums.proto"; +import "frameworks/base/core/proto/android/bluetooth/a2dp/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto"; +import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto"; import "frameworks/base/core/proto/android/net/networkcapabilities.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto"; @@ -142,6 +144,23 @@ message Atom { NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139; SeStateChanged se_state_changed = 140; SeOmapiReported se_omapi_reported = 141; + BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151; + BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed = 152; + BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed = 153; + BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed = 154; + BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported = 155; + BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported = 156; + BluetoothDeviceRssiReported bluetooth_device_rssi_reported = 157; + BluetoothDeviceFailedContactCounterReported bluetooth_device_failed_contact_counter_reported = 158; + BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported = 159; + BluetoothHciTimeoutReported bluetooth_hci_timeout_reported = 160; + BluetoothQualityReportReported bluetooth_quality_report_reported = 161; + BluetoothManufacturerInfoReported bluetooth_device_info_reported = 162; + BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported = 163; + BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported = 164; + BluetoothBondStateChanged bluetooth_bond_state_changed = 165; + BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166; + BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167; } // Pulled events will start at field 10000. @@ -1084,6 +1103,27 @@ message BluetoothScoConnectionStateChanged { optional android.bluetooth.hfp.ScoCodec codec = 3; } +/** + * Logged when active device of a profile changes + * + * Logged from: + * packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java + * packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java + * packages/apps/Bluetooth/src/com/android/bluetooth/hearingaid/HearingAidService.java + */ +message BluetoothActiveDeviceChanged { + // The profile whose active device has changed. Eg. A2DP, HEADSET, HEARING_AID + // From android.bluetooth.BluetoothProfile + optional int32 bt_profile = 1; + // An identifier that can be used to match events for this new active device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if there is no active device for this profile + optional bytes obfuscated_id = 2 [(android.os.statsd.log_mode) = MODE_BYTES]; +} + // Logs when there is an event affecting Bluetooth device's link layer connection. // - This event is triggered when there is a related HCI command or event // - Users of this metrics can deduce Bluetooth device's connection state from these events @@ -1167,6 +1207,516 @@ message BluetoothLinkLayerConnectionEvent { optional android.bluetooth.hci.StatusEnum reason_code = 9; } +/** + * Logs when there is a change in Bluetooth A2DP playback state + * + * Logged from: + * packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java + */ +message BluetoothA2dpPlaybackStateChanged { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Current playback state + // Default: PLAYBACK_STATE_UNKNOWN + optional android.bluetooth.a2dp.PlaybackStateEnum playback_state = 2; + // Current audio coding mode + // Default: AUDIO_CODING_MODE_UNKNOWN + optional android.bluetooth.a2dp.AudioCodingModeEnum audio_coding_mode = 3; +} + +/** + * Logs when there is a change in A2DP codec config for a particular remote device + * + * Logged from: + * frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java + * packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java + */ +message BluetoothA2dpCodecConfigChanged { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig + // Default SOURCE_CODEC_TYPE_INVALID + optional int32 codec_type = 2; + // Codec priroity, the higher the more preferred, -1 for disabled + // Default: CODEC_PRIORITY_DEFAULT + optional int32 codec_priority = 3; + // Sample rate in Hz as defined by various SAMPLE_RATE_* constants in BluetoothCodecConfig + // Default: SAMPLE_RATE_NONE + optional int32 sample_rate = 4; + // Bits per sample as defined by various BITS_PER_SAMPLE_* constants in BluetoothCodecConfig + // Default: BITS_PER_SAMPLE_NONE + optional int32 bits_per_sample = 5; + // Channel mode as defined by various CHANNEL_MODE_* constants in BluetoothCodecConfig + // Default: CHANNEL_MODE_NONE + optional int32 channel_mode = 6; + // Codec specific values + // Default 0 + optional int64 codec_specific_1 = 7; + optional int64 codec_specific_2 = 8; + optional int64 codec_specific_3 = 9; + optional int64 codec_specific_4 = 10; +} + +/** + * Logs when there is a change in selectable A2DP codec capability for a paricular remote device + * Each codec's capability is logged separately due to statsd restriction + * + * Logged from: + * frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java + * packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java + */ +message BluetoothA2dpCodecCapabilityChanged { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig + // Default SOURCE_CODEC_TYPE_INVALID + optional int32 codec_type = 2; + // Codec priroity, the higher the more preferred, -1 for disabled + // Default: CODEC_PRIORITY_DEFAULT + optional int32 codec_priority = 3; + // A bit field of supported sample rates as defined by various SAMPLE_RATE_* constants + // in BluetoothCodecConfig + // Default: empty and SAMPLE_RATE_NONE for individual item + optional int32 sample_rate = 4; + // A bit field of supported bits per sample as defined by various BITS_PER_SAMPLE_* constants + // in BluetoothCodecConfig + // Default: empty and BITS_PER_SAMPLE_NONE for individual item + optional int32 bits_per_sample = 5; + // A bit field of supported channel mode as defined by various CHANNEL_MODE_* constants in + // BluetoothCodecConfig + // Default: empty and CHANNEL_MODE_NONE for individual item + optional int32 channel_mode = 6; + // Codec specific values + // Default 0 + optional int64 codec_specific_1 = 7; + optional int64 codec_specific_2 = 8; + optional int64 codec_specific_3 = 9; + optional int64 codec_specific_4 = 10; +} + +/** + * Logs when A2DP failed to read from PCM source. + * This typically happens when audio HAL cannot supply A2DP with data fast enough for encoding. + * + * Logged from: + * system/bt + */ +message BluetoothA2dpAudioUnderrunReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Encoding interval in nanoseconds + // Default: 0 + optional int64 encoding_interval_nanos = 2; + // Number of bytes of PCM data that could not be read from the source + // Default: 0 + optional int32 num_missing_pcm_bytes = 3; +} + +/** + * Logs when A2DP failed send encoded data to the remote device fast enough such that the transmit + * buffer queue is full and we have to drop data + * + * Logged from: + * system/bt + */ +message BluetoothA2dpAudioOverrunReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Encoding interval in nanoseconds + // Default: 0 + optional int64 encoding_interval_nanos = 2; + // Number of buffers dropped in this event + // Each buffer is encoded in one encoding interval and consists of multiple encoded frames + // Default: 0 + optional int32 num_dropped_buffers = 3; + // Number of encoded buffers dropped in this event + // Default 0 + optional int32 num_dropped_encoded_frames = 4; + // Number of encoded bytes dropped in this event + // Default: 0 + optional int32 num_dropped_encoded_bytes = 5; +} + +/** + * Logs when we receive reports regarding a device's RSSI value + * + * Logged from: + * system/bt + */ +message BluetoothDeviceRssiReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Connection handle of this connection if available + // Range: 0x0000 - 0x0EFF (12 bits) + // Default: 0xFFFF if the handle is unknown + optional int32 connection_handle = 2; + // HCI command status code if this is triggerred by hci_cmd + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum hci_status = 3; + // BR/EDR + // Range: -128 ≤ N ≤ 127 (signed integer) + // Units: dB + // LE: + // Range: -127 to 20, 127 (signed integer) + // Units: dBm + // Invalid when an out of range value is reported + optional int32 rssi = 4; +} + +/** + * Logs when we receive reports regarding how many consecutive failed contacts for a connection + * + * Logged from: + * system/bt + */ +message BluetoothDeviceFailedContactCounterReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Connection handle of this connection if available + // Range: 0x0000 - 0x0EFF (12 bits) + // Default: 0xFFFF if the handle is unknown + optional int32 connection_handle = 2; + // HCI command status code if this is triggerred by hci_cmd + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum cmd_status = 3; + // Number of consecutive failed contacts for a connection corresponding to the Handle + // Range: uint16_t, 0-0xFFFF + // Default: 0xFFFFF + optional int32 failed_contact_counter = 4; +} + +/** + * Logs when we receive reports regarding the tranmit power level used for a specific connection + * + * Logged from: + * system/bt + */ +message BluetoothDeviceTxPowerLevelReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Connection handle of this connection if available + // Range: 0x0000 - 0x0EFF (12 bits) + // Default: 0xFFFF if the handle is unknown + optional int32 connection_handle = 2; + // HCI command status code if this is triggered by hci_cmd + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum hci_status = 3; + // Range: -30 ≤ N ≤ 20 + // Units: dBm + // Invalid when an out of range value is reported + optional int32 transmit_power_level = 4; +} + +/** + * Logs when Bluetooth controller failed to reply with command status within a timeout period after + * receiving an HCI command from the host + * + * Logged from: system/bt + */ +message BluetoothHciTimeoutReported { + // HCI command associated with this event + // Default: CMD_UNKNOWN + optional android.bluetooth.hci.CommandEnum hci_command = 1; +} + +/** + * Logs when we receive Bluetooth Link Quality Report event from the controller + * See Android Bluetooth HCI specification for more details + * + * Note: all count and bytes field are counted since last event + * + * Logged from: system/bt + */ +message BluetoothQualityReportReported { + // Quality report ID + // Original type: uint8_t + // Default: BQR_ID_UNKNOWN + optional android.bluetooth.hci.BqrIdEnum quality_report_id = 1; + // Packet type of the connection + // Original type: uint8_t + // Default: BQR_PACKET_TYPE_UNKNOWN + optional android.bluetooth.hci.BqrPacketTypeEnum packet_types = 2; + // Connection handle of the connection + // Original type: uint16_t + optional int32 connection_handle = 3; + // Performing Role for the connection + // Original type: uint8_t + optional int32 connection_role = 4; + // Current Transmit Power Level for the connection. This value is the same as the controller's + // response to the HCI_Read_Transmit_Power_Level HCI command + // Original type: uint8_t + optional int32 tx_power_level = 5; + // Received Signal Strength Indication (RSSI) value for the connection. This value is an + // absolute receiver signal strength value + // Original type: int8_t + optional int32 rssi = 6; + // Signal-to-Noise Ratio (SNR) value for the connection. It is the average SNR of all the + // channels used by the link currently + // Original type: uint8_t + optional int32 snr = 7; + // Indicates the number of unused channels in AFH_channel_map + // Original type: uint8_t + optional int32 unused_afh_channel_count = 8; + // Indicates the number of the channels which are interfered and quality is bad but are still + // selected for AFH + // Original type: uint8_t + optional int32 afh_select_unideal_channel_count = 9; + // Current Link Supervision Timeout Setting + // Unit: N * 0.3125 ms (1 Bluetooth Clock) + // Original type: uint16_t + optional int32 lsto = 10; + // Piconet Clock for the specified Connection_Handle. This value is the same as the controller's + // response to HCI_Read_Clock HCI command with the parameter "Which_Clock" of + // 0x01 (Piconet Clock) + // Unit: N * 0.3125 ms (1 Bluetooth Clock) + // Original type: uint32_t + optional int64 connection_piconet_clock = 11; + // The count of retransmission + // Original type: uint32_t + optional int64 retransmission_count = 12; + // The count of no RX + // Original type: uint32_t + optional int64 no_rx_count = 13; + // The count of NAK (Negative Acknowledge) + // Original type: uint32_t + optional int64 nak_count = 14; + // Controller timestamp of last TX ACK + // Unit: N * 0.3125 ms (1 Bluetooth Clock) + // Original type: uint32_t + optional int64 last_tx_ack_timestamp = 15; + // The count of Flow-off (STOP) + // Original type: uint32_t + optional int64 flow_off_count = 16; + // Controller timestamp of last Flow-on (GO) + // Unit: N * 0.3125 ms (1 Bluetooth Clock) + // Original type: uint32_t + optional int64 last_flow_on_timestamp = 17; + // Buffer overflow count (how many bytes of TX data are dropped) since the last event + // Original type: uint32_t + optional int64 buffer_overflow_bytes = 18; + // Buffer underflow count (in byte) since last event + // Original type: uint32_t + optional int64 buffer_underflow_bytes = 19; +} + +/** + * Logs when a Bluetooth device's manufacturer information is learnt by the Bluetooth stack + * + * Notes: + * - Each event can be partially filled as we might learn different pieces of device + * information at different time + * - Multiple device info events can be combined to give more complete picture + * - When multiple device info events tries to describe the same information, the + * later one wins + * + * Logged from: + * packages/apps/Bluetooth + */ +message BluetoothManufacturerInfoReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Where is this device info obtained from + optional android.bluetooth.DeviceInfoSrcEnum source_type = 2; + // Name of the data source + // For EXTERNAL: package name of the data source + // For INTERNAL: null for general case, component name otherwise + optional string source_name = 3; + // Name of the manufacturer of this device + optional string manufacturer = 4; + // Model of this device + optional string model = 5; + // Hardware version of this device + optional string hardware_version = 6; + // Software version of this device + optional string software_version = 7; +} + +/** + * Logs when we receive Bluetooth Read Remote Version Information Complete Event from the remote + * device, as documented by the Bluetooth Core HCI specification + * Reference: https://www.bluetooth.com/specifications/bluetooth-core-specification + * Vol 2, Part E, Page 1118 + * + * Logged from: + * system/bt + */ +message BluetoothRemoteVersionInfoReported { + // Connection handle of the connection + // Original type: uint16_t + optional int32 connection_handle = 1; + // HCI command status code + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum hci_status = 2; + // 1 byte Version of current LMP in the remote controller + optional int32 lmp_version = 3; + // 2 bytes LMP manufacturer code of the remote controller + // https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers + optional int32 lmp_manufacturer_code = 4; + // 4 bytes subversion of the LMP in the remote controller + optional int32 lmp_subversion = 5; +} + +/** + * Logs when certain Bluetooth SDP attributes are discovered + * Constant definitions are from: + * https://www.bluetooth.com/specifications/assigned-numbers/service-discovery + * + * Current logged attributes: + * - BluetoothProfileDescriptorList + * - Supported Features Bitmask + * + * Logged from: + * system/bt + */ +message BluetoothSdpAttributeReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Short form UUIDs used to identify Bluetooth protocols, profiles, and service classes + // Original type: uint16_t + optional int32 protocol_uuid = 2; + // Short form UUIDs used to identify Bluetooth SDP attribute types + // Original type: uint16_t + optional int32 attribute_id = 3; + // Attribute value for the particular attribute + optional bytes attribute_value = 4 [(android.os.statsd.log_mode) = MODE_BYTES]; +} + +/** + * Logs when bond state of a Bluetooth device changes + * + * Logged from: + * frameworks/base/core/java/android/bluetooth/BluetoothDevice.java + * packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java + */ +message BluetoothBondStateChanged { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Preferred transport type to remote dual mode device + // Default: TRANSPORT_AUTO means no preference + optional android.bluetooth.TransportTypeEnum transport = 2; + // The type of this Bluetooth device (Classic, LE, or Dual mode) + // Default: UNKNOWN + optional android.bluetooth.DeviceTypeEnum type = 3; + // Current bond state (NONE, BONDING, BONDED) + // Default: BOND_STATE_UNKNOWN + optional android.bluetooth.BondStateEnum bond_state = 4; + // Bonding sub state + // Default: BOND_SUB_STATE_UNKNOWN + optional android.bluetooth.BondSubStateEnum bonding_sub_state = 5; + // Unbond Reason + // Default: UNBOND_REASON_UNKNOWN + optional android.bluetooth.UnbondReasonEnum unbond_reason = 6; +} + +/** + * Logs there is an event related Bluetooth classic pairing + * + * Logged from: + * system/bt + */ +message BluetoothClassicPairingEventReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // Connection handle of this connection if available + // Range: 0x0000 - 0x0EFF (12 bits) + // Default: 0xFFFF if the handle is unknown + optional int32 connection_handle = 2; + // HCI command associated with this event + // Default: CMD_UNKNOWN + optional android.bluetooth.hci.CommandEnum hci_cmd = 3; + // HCI event associated with this event + // Default: EVT_UNKNOWN + optional android.bluetooth.hci.EventEnum hci_event = 4; + // HCI command status code if this is triggerred by hci_cmd + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum cmd_status = 5; + // HCI reason code associated with this event + // Default: STATUS_UNKNOWN + optional android.bluetooth.hci.StatusEnum reason_code = 6; +} + +/** + * Logs when there is an event related to Bluetooth Security Manager Protocol (SMP) + * + * Logged from: + * system/bt + */ +message BluetoothSmpPairingEventReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES]; + // SMP command sent or received over L2CAP + // Default: CMD_UNKNOWN + optional android.bluetooth.smp.CommandEnum smp_command = 2; + // Whether this command is sent or received + // Default: DIRECTION_UNKNOWN + optional android.bluetooth.DirectionEnum direction = 3; + // SMP failure reason code + // Default: PAIRING_FAIL_REASON_DEFAULT + optional android.bluetooth.smp.PairingFailReasonEnum smp_fail_reason = 4; +} /** * Logs when something is plugged into or removed from the USB-C connector. diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index d2f246846ce3..b2951df63ebd 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -84,6 +84,7 @@ import android.net.IConnectivityManager; import android.net.IEthernetManager; import android.net.IIpMemoryStore; import android.net.IIpSecService; +import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.IpMemoryStore; import android.net.IpSecManager; @@ -288,6 +289,14 @@ final class SystemServiceRegistry { return new ConnectivityManager(context, service); }}); + registerService(Context.NETD_SERVICE, INetd.class, new StaticServiceFetcher<INetd>() { + @Override + public INetd createService() throws ServiceNotFoundException { + return INetd.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.NETD_SERVICE)); + } + }); + registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class, new StaticServiceFetcher<NetworkStack>() { @Override diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 1b08ecd32fca..18a006ffff31 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4464,11 +4464,16 @@ public class DevicePolicyManager { } /** + * Service-specific error code used in implementation of {@code setAlwaysOnVpnPackage} methods. + * @hide + */ + public static final int ERROR_VPN_PACKAGE_NOT_FOUND = 1; + + /** * Called by a device or profile owner to configure an always-on VPN connection through a * specific application for the current user. This connection is automatically granted and * persisted after a reboot. - * <p> - * To support the always-on feature, an app must + * <p> To support the always-on feature, an app must * <ul> * <li>declare a {@link android.net.VpnService} in its manifest, guarded by * {@link android.Manifest.permission#BIND_VPN_SERVICE};</li> @@ -4477,25 +4482,61 @@ public class DevicePolicyManager { * {@link android.net.VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}.</li> * </ul> * The call will fail if called with the package name of an unsupported VPN app. + * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure + * of the VPN provider could break networking for all apps. * * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to * remove an existing always-on VPN configuration. * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or - * {@code false} otherwise. This carries the risk that any failure of the VPN provider - * could break networking for all apps. This has no effect when clearing. + * {@code false} otherwise. This has no effect when clearing. * @throws SecurityException if {@code admin} is not a device or a profile owner. * @throws NameNotFoundException if {@code vpnPackage} is not installed. * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being * set as always-on, or if always-on VPN is not available. + * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List) */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, - boolean lockdownEnabled) - throws NameNotFoundException, UnsupportedOperationException { + boolean lockdownEnabled) throws NameNotFoundException { + setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList()); + } + + /** + * A version of {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} that allows the + * admin to specify a set of apps that should be able to access the network directly when VPN + * is not connected. When VPN connects these apps switch over to VPN if allowed to use that VPN. + * System apps can always bypass VPN. + * <p> Note that the system doesn't update the whitelist when packages are installed or + * uninstalled, the admin app must call this method to keep the list up to date. + * + * @param vpnPackage package name for an installed VPN app on the device, or {@code null} + * to remove an existing always-on VPN configuration + * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or + * {@code false} otherwise. This has no effect when clearing. + * @param lockdownWhitelist Packages that will be able to access the network directly when VPN + * is in lockdown mode but not connected. Has no effect when clearing. + * @throws SecurityException if {@code admin} is not a device or a profile + * owner. + * @throws NameNotFoundException if {@code vpnPackage} or one of + * {@code lockdownWhitelist} is not installed. + * @throws UnsupportedOperationException if {@code vpnPackage} exists but does + * not support being set as always-on, or if always-on VPN is not + * available. + */ + public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, + boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) + throws NameNotFoundException { throwIfParentInstance("setAlwaysOnVpnPackage"); if (mService != null) { try { - if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled)) { - throw new NameNotFoundException(vpnPackage); + mService.setAlwaysOnVpnPackage( + admin, vpnPackage, lockdownEnabled, lockdownWhitelist); + } catch (ServiceSpecificException e) { + switch (e.errorCode) { + case ERROR_VPN_PACKAGE_NOT_FOUND: + throw new NameNotFoundException(e.getMessage()); + default: + throw new RuntimeException( + "Unknown error setting always-on VPN: " + e.errorCode, e); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -4504,6 +4545,51 @@ public class DevicePolicyManager { } /** + * Called by device or profile owner to query whether current always-on VPN is configured in + * lockdown mode. Returns {@code false} when no always-on configuration is set. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * + * @throws SecurityException if {@code admin} is not a device or a profile owner. + * + * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean) + */ + public boolean isAlwaysOnVpnLockdownEnabled(@NonNull ComponentName admin) { + throwIfParentInstance("isAlwaysOnVpnLockdownEnabled"); + if (mService != null) { + try { + return mService.isAlwaysOnVpnLockdownEnabled(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Called by device or profile owner to query the list of packages that are allowed to access + * the network directly when always-on VPN is in lockdown mode but not connected. Returns + * {@code null} when always-on VPN is not active or not in lockdown mode. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * + * @throws SecurityException if {@code admin} is not a device or a profile owner. + * + * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List) + */ + public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) { + throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist"); + if (mService != null) { + try { + return mService.getAlwaysOnVpnLockdownWhitelist(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Called by a device or profile owner to read the name of the package administering an * always-on VPN connection for the current user. If there is no such package, or the always-on * VPN is provided by the system instead of by an application, {@code null} will be returned. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 37508cdc1119..00463028a685 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -182,8 +182,10 @@ interface IDevicePolicyManager { void setCertInstallerPackage(in ComponentName who, String installerPackage); String getCertInstallerPackage(in ComponentName who); - boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown); + boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist); String getAlwaysOnVpnPackage(in ComponentName who); + boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who); + List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who); void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 29161cce2ca0..8959540ff7c3 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3506,6 +3506,16 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.net.INetd} for communicating with the network stack + * @hide + * @see #getSystemService(String) + * @hide + */ + @SystemApi + public static final String NETD_SERVICE = "netd"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link NetworkStack} for communicating with the network stack * @hide * @see #getSystemService(String) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2130c39a8905..92c757ceaa29 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -5501,7 +5501,7 @@ public abstract class PackageManager { * @param newState The new enabled state for the component. * @param flags Optional behavior flags. */ - public abstract void setComponentEnabledSetting(ComponentName componentName, + public abstract void setComponentEnabledSetting(@NonNull ComponentName componentName, @EnabledState int newState, @EnabledFlags int flags); /** @@ -5515,7 +5515,7 @@ public abstract class PackageManager { * @return Returns the current enabled state for the component. */ public abstract @EnabledState int getComponentEnabledSetting( - ComponentName componentName); + @NonNull ComponentName componentName); /** * Set the enabled setting for an application @@ -5528,7 +5528,7 @@ public abstract class PackageManager { * @param newState The new enabled state for the application. * @param flags Optional behavior flags. */ - public abstract void setApplicationEnabledSetting(String packageName, + public abstract void setApplicationEnabledSetting(@NonNull String packageName, @EnabledState int newState, @EnabledFlags int flags); /** @@ -5542,7 +5542,7 @@ public abstract class PackageManager { * @return Returns the current enabled state for the application. * @throws IllegalArgumentException if the named package does not exist. */ - public abstract @EnabledState int getApplicationEnabledSetting(String packageName); + public abstract @EnabledState int getApplicationEnabledSetting(@NonNull String packageName); /** * Flush the package restrictions for a given user to disk. This forces the package restrictions diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index 3b0126673779..3ab35e1eebf0 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -117,4 +117,17 @@ public class CaptivePortal implements Parcelable { } catch (RemoteException e) { } } + + /** + * Log a captive portal login event. + * @hide + */ + @SystemApi + @TestApi + public void logEvent(int eventId, String packageName) { + try { + ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2ecc647d64d9..f807924e752d 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1014,20 +1014,26 @@ public class ConnectivityManager { * to remove an existing always-on VPN configuration. * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or * {@code false} otherwise. + * @param lockdownWhitelist The list of packages that are allowed to access network directly + * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so + * this method must be called when a package that should be whitelisted is installed or + * uninstalled. * @return {@code true} if the package is set as always-on VPN controller; * {@code false} otherwise. * @hide */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled) { + boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) { try { - return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled); + return mService.setAlwaysOnVpnPackage( + userId, vpnPackage, lockdownEnabled, lockdownWhitelist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - /** + /** * Returns the package name of the currently set always-on VPN application. * If there is no always-on VPN set, or the VPN is provided by the system instead * of by an app, {@code null} will be returned. @@ -1036,6 +1042,7 @@ public class ConnectivityManager { * or {@code null} if none is set. * @hide */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) public String getAlwaysOnVpnPackageForUser(int userId) { try { return mService.getAlwaysOnVpnPackage(userId); @@ -1045,6 +1052,36 @@ public class ConnectivityManager { } /** + * @return whether always-on VPN is in lockdown mode. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public boolean isVpnLockdownEnabled(int userId) { + try { + return mService.isVpnLockdownEnabled(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + + /** + * @return the list of packages that are allowed to access network when always-on VPN is in + * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public List<String> getVpnLockdownWhitelist(int userId) { + try { + return mService.getVpnLockdownWhitelist(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns details about the currently active default data network * for a given uid. This is for internal use only to avoid spying * other apps. diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java index b5d822672e70..6f9e65fdf12c 100644 --- a/core/java/android/net/DhcpResults.java +++ b/core/java/android/net/DhcpResults.java @@ -17,24 +17,40 @@ package android.net; import android.annotation.UnsupportedAppUsage; -import android.net.NetworkUtils; +import android.net.shared.InetAddressUtils; import android.os.Parcel; +import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; import java.net.Inet4Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** * A simple object for retrieving the results of a DHCP request. * Optimized (attempted) for that jni interface - * TODO - remove when DhcpInfo is deprecated. Move the remaining api to LinkProperties. + * TODO: remove this class and replace with other existing constructs * @hide */ -public class DhcpResults extends StaticIpConfiguration { +public final class DhcpResults implements Parcelable { private static final String TAG = "DhcpResults"; @UnsupportedAppUsage + public LinkAddress ipAddress; + + @UnsupportedAppUsage + public InetAddress gateway; + + @UnsupportedAppUsage + public final ArrayList<InetAddress> dnsServers = new ArrayList<>(); + + @UnsupportedAppUsage + public String domains; + + @UnsupportedAppUsage public Inet4Address serverAddress; /** Vendor specific information (from RFC 2132). */ @@ -48,23 +64,38 @@ public class DhcpResults extends StaticIpConfiguration { @UnsupportedAppUsage public int mtu; - @UnsupportedAppUsage public DhcpResults() { super(); } - @UnsupportedAppUsage + /** + * Create a {@link StaticIpConfiguration} based on the DhcpResults. + */ + public StaticIpConfiguration toStaticIpConfiguration() { + final StaticIpConfiguration s = new StaticIpConfiguration(); + // All these except dnsServers are immutable, so no need to make copies. + s.setIpAddress(ipAddress); + s.setGateway(gateway); + for (InetAddress addr : dnsServers) { + s.addDnsServer(addr); + } + s.setDomains(domains); + return s; + } + public DhcpResults(StaticIpConfiguration source) { - super(source); + if (source != null) { + ipAddress = source.getIpAddress(); + gateway = source.getGateway(); + dnsServers.addAll(source.getDnsServers()); + domains = source.getDomains(); + } } /** copy constructor */ - @UnsupportedAppUsage public DhcpResults(DhcpResults source) { - super(source); - + this(source == null ? null : source.toStaticIpConfiguration()); if (source != null) { - // All these are immutable, so no need to make copies. serverAddress = source.serverAddress; vendorInfo = source.vendorInfo; leaseDuration = source.leaseDuration; @@ -73,6 +104,14 @@ public class DhcpResults extends StaticIpConfiguration { } /** + * @see StaticIpConfiguration#getRoutes(String) + * @hide + */ + public List<RouteInfo> getRoutes(String iface) { + return toStaticIpConfiguration().getRoutes(iface); + } + + /** * Test if this DHCP lease includes vendor hint that network link is * metered, and sensitive to heavy data transfers. */ @@ -85,7 +124,11 @@ public class DhcpResults extends StaticIpConfiguration { } public void clear() { - super.clear(); + ipAddress = null; + gateway = null; + dnsServers.clear(); + domains = null; + serverAddress = null; vendorInfo = null; leaseDuration = 0; mtu = 0; @@ -111,20 +154,20 @@ public class DhcpResults extends StaticIpConfiguration { DhcpResults target = (DhcpResults)obj; - return super.equals((StaticIpConfiguration) obj) && - Objects.equals(serverAddress, target.serverAddress) && - Objects.equals(vendorInfo, target.vendorInfo) && - leaseDuration == target.leaseDuration && - mtu == target.mtu; + return toStaticIpConfiguration().equals(target.toStaticIpConfiguration()) + && Objects.equals(serverAddress, target.serverAddress) + && Objects.equals(vendorInfo, target.vendorInfo) + && leaseDuration == target.leaseDuration + && mtu == target.mtu; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + */ public static final Creator<DhcpResults> CREATOR = new Creator<DhcpResults>() { public DhcpResults createFromParcel(Parcel in) { - DhcpResults dhcpResults = new DhcpResults(); - readFromParcel(dhcpResults, in); - return dhcpResults; + return readFromParcel(in); } public DhcpResults[] newArray(int size) { @@ -134,26 +177,33 @@ public class DhcpResults extends StaticIpConfiguration { /** Implement the Parcelable interface */ public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); + toStaticIpConfiguration().writeToParcel(dest, flags); dest.writeInt(leaseDuration); dest.writeInt(mtu); - NetworkUtils.parcelInetAddress(dest, serverAddress, flags); + InetAddressUtils.parcelInetAddress(dest, serverAddress, flags); dest.writeString(vendorInfo); } - private static void readFromParcel(DhcpResults dhcpResults, Parcel in) { - StaticIpConfiguration.readFromParcel(dhcpResults, in); + @Override + public int describeContents() { + return 0; + } + + private static DhcpResults readFromParcel(Parcel in) { + final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in); + final DhcpResults dhcpResults = new DhcpResults(s); dhcpResults.leaseDuration = in.readInt(); dhcpResults.mtu = in.readInt(); - dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in); + dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in); dhcpResults.vendorInfo = in.readString(); + return dhcpResults; } // Utils for jni population - false on success // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon. public boolean setIpAddress(String addrString, int prefixLength) { try { - Inet4Address addr = (Inet4Address) NetworkUtils.numericToInetAddress(addrString); + Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString); ipAddress = new LinkAddress(addr, prefixLength); } catch (IllegalArgumentException|ClassCastException e) { Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength); @@ -164,7 +214,7 @@ public class DhcpResults extends StaticIpConfiguration { public boolean setGateway(String addrString) { try { - gateway = NetworkUtils.numericToInetAddress(addrString); + gateway = InetAddresses.parseNumericAddress(addrString); } catch (IllegalArgumentException e) { Log.e(TAG, "setGateway failed with addrString " + addrString); return true; @@ -175,7 +225,7 @@ public class DhcpResults extends StaticIpConfiguration { public boolean addDns(String addrString) { if (TextUtils.isEmpty(addrString) == false) { try { - dnsServers.add(NetworkUtils.numericToInetAddress(addrString)); + dnsServers.add(InetAddresses.parseNumericAddress(addrString)); } catch (IllegalArgumentException e) { Log.e(TAG, "addDns failed with addrString " + addrString); return true; @@ -184,25 +234,70 @@ public class DhcpResults extends StaticIpConfiguration { return false; } - public boolean setServerAddress(String addrString) { - try { - serverAddress = (Inet4Address) NetworkUtils.numericToInetAddress(addrString); - } catch (IllegalArgumentException|ClassCastException e) { - Log.e(TAG, "setServerAddress failed with addrString " + addrString); - return true; - } - return false; + public LinkAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(LinkAddress ipAddress) { + this.ipAddress = ipAddress; + } + + public InetAddress getGateway() { + return gateway; + } + + public void setGateway(InetAddress gateway) { + this.gateway = gateway; + } + + public List<InetAddress> getDnsServers() { + return dnsServers; + } + + /** + * Add a DNS server to this configuration. + */ + public void addDnsServer(InetAddress server) { + dnsServers.add(server); + } + + public String getDomains() { + return domains; + } + + public void setDomains(String domains) { + this.domains = domains; + } + + public Inet4Address getServerAddress() { + return serverAddress; + } + + public void setServerAddress(Inet4Address addr) { + serverAddress = addr; + } + + public int getLeaseDuration() { + return leaseDuration; } public void setLeaseDuration(int duration) { leaseDuration = duration; } + public String getVendorInfo() { + return vendorInfo; + } + public void setVendorInfo(String info) { vendorInfo = info; } - public void setDomains(String newDomains) { - domains = newDomains; + public int getMtu() { + return mtu; + } + + public void setMtu(int mtu) { + this.mtu = mtu; } } diff --git a/core/java/android/net/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl index 56ae57dc0e8d..707b4f699873 100644 --- a/core/java/android/net/ICaptivePortal.aidl +++ b/core/java/android/net/ICaptivePortal.aidl @@ -22,4 +22,5 @@ package android.net; */ oneway interface ICaptivePortal { void appResponse(int response); + void logEvent(int eventId, String packageName); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 949b772537bb..78fafebc4f37 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -125,8 +125,11 @@ interface IConnectivityManager boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); - boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); + boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown, + in List<String> lockdownWhitelist); String getAlwaysOnVpnPackage(int userId); + boolean isVpnLockdownEnabled(int userId); + List<String> getVpnLockdownWhitelist(int userId); int checkMobileProvisioning(int suggestedTimeOutMs); diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl index 0bc25750129b..a8682f9ddd3b 100644 --- a/core/java/android/net/INetworkMonitorCallbacks.aidl +++ b/core/java/android/net/INetworkMonitorCallbacks.aidl @@ -26,4 +26,5 @@ oneway interface INetworkMonitorCallbacks { void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config); void showProvisioningNotification(String action); void hideProvisioningNotification(); + void logCaptivePortalLoginEvent(int eventId, String packageName); }
\ No newline at end of file diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl index 8b64f1c7c45a..e052488f38c8 100644 --- a/core/java/android/net/INetworkStackConnector.aidl +++ b/core/java/android/net/INetworkStackConnector.aidl @@ -16,6 +16,7 @@ package android.net; import android.net.INetworkMonitorCallbacks; +import android.net.NetworkParcelable; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpServerCallbacks; import android.net.ip.IIpClientCallbacks; @@ -24,6 +25,7 @@ import android.net.ip.IIpClientCallbacks; oneway interface INetworkStackConnector { void makeDhcpServer(in String ifName, in DhcpServingParamsParcel params, in IDhcpServerCallbacks cb); - void makeNetworkMonitor(int netId, String name, in INetworkMonitorCallbacks cb); + void makeNetworkMonitor(in NetworkParcelable network, String name, + in INetworkMonitorCallbacks cb); void makeIpClient(in String ifName, in IIpClientCallbacks callbacks); }
\ No newline at end of file diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index b996cdab5164..175263f0adaa 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -104,6 +104,8 @@ public final class IpPrefix implements Parcelable { * * @hide */ + @SystemApi + @TestApi public IpPrefix(String prefix) { // We don't reuse the (InetAddress, int) constructor because "error: call to this must be // first statement in constructor". We could factor out setting the member variables to an diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index fbd602c7b2d0..8d779aaa2312 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -176,6 +176,7 @@ public class LinkAddress implements Parcelable { * @hide */ @SystemApi + @TestApi public LinkAddress(InetAddress address, int prefixLength) { this(address, prefixLength, 0, 0); this.scope = scopeForUnicastAddress(address); @@ -199,6 +200,7 @@ public class LinkAddress implements Parcelable { * @hide */ @SystemApi + @TestApi public LinkAddress(String address) { this(address, 0, 0); this.scope = scopeForUnicastAddress(this.address); @@ -212,6 +214,8 @@ public class LinkAddress implements Parcelable { * @param scope The address scope. * @hide */ + @SystemApi + @TestApi public LinkAddress(String address, int flags, int scope) { // This may throw an IllegalArgumentException; catching it is the caller's responsibility. // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24". diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 662870182eea..42db0fd7cb8c 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -287,7 +287,8 @@ public final class LinkProperties implements Parcelable { * @return true if {@code address} was added or updated, false otherwise. * @hide */ - @UnsupportedAppUsage + @SystemApi + @TestApi public boolean addLinkAddress(LinkAddress address) { if (address == null) { return false; @@ -315,6 +316,8 @@ public final class LinkProperties implements Parcelable { * @return true if the address was removed, false if it did not exist. * @hide */ + @SystemApi + @TestApi public boolean removeLinkAddress(LinkAddress toRemove) { int i = findLinkAddressIndex(toRemove); if (i >= 0) { diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 2c831de72051..e04b5fc5f9cf 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -123,6 +123,8 @@ public class Network implements Parcelable { /** * @hide */ + @SystemApi + @TestApi public Network(Network that) { this(that.netId, that.mPrivateDnsBypass); } diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java index d277034650a1..ac6bff029e8c 100644 --- a/core/java/android/net/NetworkStack.java +++ b/core/java/android/net/NetworkStack.java @@ -104,10 +104,11 @@ public class NetworkStack { * * <p>The INetworkMonitor will be returned asynchronously through the provided callbacks. */ - public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) { + public void makeNetworkMonitor( + NetworkParcelable network, String name, INetworkMonitorCallbacks cb) { requestConnector(connector -> { try { - connector.makeNetworkMonitor(network.netId, name, cb); + connector.makeNetworkMonitor(network, name, cb); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 7f4d8cd1cfcb..07668a9e3a82 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -17,8 +17,9 @@ package android.net; import android.annotation.UnsupportedAppUsage; +import android.net.shared.Inet4AddressUtils; import android.os.Build; -import android.os.Parcel; +import android.system.ErrnoException; import android.util.Log; import android.util.Pair; @@ -34,8 +35,6 @@ import java.util.Collection; import java.util.Locale; import java.util.TreeSet; -import android.system.ErrnoException; - /** * Native methods for managing network interfaces. * @@ -172,119 +171,37 @@ public class NetworkUtils { FileDescriptor fd) throws IOException; /** - * @see #intToInet4AddressHTL(int) - * @deprecated Use either {@link #intToInet4AddressHTH(int)} - * or {@link #intToInet4AddressHTL(int)} + * @see Inet4AddressUtils#intToInet4AddressHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)} + * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)} */ @Deprecated @UnsupportedAppUsage public static InetAddress intToInetAddress(int hostAddress) { - return intToInet4AddressHTL(hostAddress); + return Inet4AddressUtils.intToInet4AddressHTL(hostAddress); } /** - * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4) - * - * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes, - * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead. - * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is - * lower-order IPv4 address byte - */ - public static Inet4Address intToInet4AddressHTL(int hostAddress) { - return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); - } - - /** - * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) - * @param hostAddress an int coding for an IPv4 address - */ - public static Inet4Address intToInet4AddressHTH(int hostAddress) { - byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), - (byte) (0xff & (hostAddress >> 16)), - (byte) (0xff & (hostAddress >> 8)), - (byte) (0xff & hostAddress) }; - - try { - return (Inet4Address) InetAddress.getByAddress(addressBytes); - } catch (UnknownHostException e) { - throw new AssertionError(); - } - } - - /** - * @see #inet4AddressToIntHTL(Inet4Address) - * @deprecated Use either {@link #inet4AddressToIntHTH(Inet4Address)} - * or {@link #inet4AddressToIntHTL(Inet4Address)} + * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address) + * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)} + * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)} */ @Deprecated public static int inetAddressToInt(Inet4Address inetAddr) throws IllegalArgumentException { - return inet4AddressToIntHTL(inetAddr); - } - - /** - * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304) - * - * <p>This conversion can help order IP addresses: considering the ordering - * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned - * integers with {@link Integer#toUnsignedLong}. - * @param inetAddr is an InetAddress corresponding to the IPv4 address - * @return the IP address as integer - */ - public static int inet4AddressToIntHTH(Inet4Address inetAddr) - throws IllegalArgumentException { - byte [] addr = inetAddr.getAddress(); - return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16) - | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff); + return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr); } /** - * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201) - * - * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes, - * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead. - * @param inetAddr is an InetAddress corresponding to the IPv4 address - * @return the IP address as integer - */ - public static int inet4AddressToIntHTL(Inet4Address inetAddr) { - return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr)); - } - - /** - * @see #prefixLengthToV4NetmaskIntHTL(int) - * @deprecated Use either {@link #prefixLengthToV4NetmaskIntHTH(int)} - * or {@link #prefixLengthToV4NetmaskIntHTL(int)} + * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)} + * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)} */ @Deprecated @UnsupportedAppUsage public static int prefixLengthToNetmaskInt(int prefixLength) throws IllegalArgumentException { - return prefixLengthToV4NetmaskIntHTL(prefixLength); - } - - /** - * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000) - * @return the IPv4 netmask as an integer - */ - public static int prefixLengthToV4NetmaskIntHTH(int prefixLength) - throws IllegalArgumentException { - if (prefixLength < 0 || prefixLength > 32) { - throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); - } - // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1) - return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength); - } - - /** - * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff). - * - * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes, - * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead. - * @return the IPv4 netmask as an integer - */ - public static int prefixLengthToV4NetmaskIntHTL(int prefixLength) - throws IllegalArgumentException { - return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength)); + return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength); } /** @@ -302,17 +219,13 @@ public class NetworkUtils { * @return the network prefix length * @throws IllegalArgumentException the specified netmask was not contiguous. * @hide + * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)} */ @UnsupportedAppUsage + @Deprecated public static int netmaskToPrefixLength(Inet4Address netmask) { - // inetAddressToInt returns an int in *network* byte order. - int i = Integer.reverseBytes(inetAddressToInt(netmask)); - int prefixLength = Integer.bitCount(i); - int trailingZeros = Integer.numberOfTrailingZeros(i); - if (trailingZeros != 32 - prefixLength) { - throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); - } - return prefixLength; + // This is only here because some apps seem to be using it (@UnsupportedAppUsage). + return Inet4AddressUtils.netmaskToPrefixLength(netmask); } @@ -333,32 +246,6 @@ public class NetworkUtils { } /** - * Writes an InetAddress to a parcel. The address may be null. This is likely faster than - * calling writeSerializable. - */ - protected static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { - byte[] addressArray = (address != null) ? address.getAddress() : null; - parcel.writeByteArray(addressArray); - } - - /** - * Reads an InetAddress from a parcel. Returns null if the address that was written was null - * or if the data is invalid. - */ - protected static InetAddress unparcelInetAddress(Parcel in) { - byte[] addressArray = in.createByteArray(); - if (addressArray == null) { - return null; - } - try { - return InetAddress.getByAddress(addressArray); - } catch (UnknownHostException e) { - return null; - } - } - - - /** * Masks a raw IP address byte array with the specified prefix length. */ public static void maskRawAddress(byte[] array, int prefixLength) { @@ -403,16 +290,8 @@ public class NetworkUtils { */ @UnsupportedAppUsage public static int getImplicitNetmask(Inet4Address address) { - int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. - if (firstByte < 128) { - return 8; - } else if (firstByte < 192) { - return 16; - } else if (firstByte < 224) { - return 24; - } else { - return 32; // Will likely not end well for other reasons. - } + // Only here because it seems to be used by apps + return Inet4AddressUtils.getImplicitNetmask(address); } /** @@ -440,28 +319,6 @@ public class NetworkUtils { } /** - * Get a prefix mask as Inet4Address for a given prefix length. - * - * <p>For example 20 -> 255.255.240.0 - */ - public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) - throws IllegalArgumentException { - return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); - } - - /** - * Get the broadcast address for a given prefix. - * - * <p>For example 192.168.0.1/24 -> 192.168.0.255 - */ - public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) - throws IllegalArgumentException { - final int intBroadcastAddr = inet4AddressToIntHTH(addr) - | ~prefixLengthToV4NetmaskIntHTH(prefixLength); - return intToInet4AddressHTH(intBroadcastAddr); - } - - /** * Check if IP address type is consistent between two InetAddress. * @return true if both are the same type. False otherwise. */ diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 3aa56b90251f..99cf3a99f57a 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -16,10 +16,12 @@ package android.net; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; -import android.net.LinkAddress; -import android.os.Parcelable; +import android.net.shared.InetAddressUtils; import android.os.Parcel; +import android.os.Parcelable; import java.net.InetAddress; import java.util.ArrayList; @@ -46,17 +48,22 @@ import java.util.Objects; * * @hide */ -public class StaticIpConfiguration implements Parcelable { +@SystemApi +@TestApi +public final class StaticIpConfiguration implements Parcelable { + /** @hide */ @UnsupportedAppUsage public LinkAddress ipAddress; + /** @hide */ @UnsupportedAppUsage public InetAddress gateway; + /** @hide */ @UnsupportedAppUsage public final ArrayList<InetAddress> dnsServers; + /** @hide */ @UnsupportedAppUsage public String domains; - @UnsupportedAppUsage public StaticIpConfiguration() { dnsServers = new ArrayList<InetAddress>(); } @@ -79,6 +86,41 @@ public class StaticIpConfiguration implements Parcelable { domains = null; } + public LinkAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(LinkAddress ipAddress) { + this.ipAddress = ipAddress; + } + + public InetAddress getGateway() { + return gateway; + } + + public void setGateway(InetAddress gateway) { + this.gateway = gateway; + } + + public List<InetAddress> getDnsServers() { + return dnsServers; + } + + public String getDomains() { + return domains; + } + + public void setDomains(String newDomains) { + domains = newDomains; + } + + /** + * Add a DNS server to this configuration. + */ + public void addDnsServer(InetAddress server) { + dnsServers.add(server); + } + /** * Returns the network routes specified by this object. Will typically include a * directly-connected route for the IP address's local subnet and a default route. If the @@ -86,7 +128,6 @@ public class StaticIpConfiguration implements Parcelable { * route to the gateway as well. This configuration is arguably invalid, but it used to work * in K and earlier, and other OSes appear to accept it. */ - @UnsupportedAppUsage public List<RouteInfo> getRoutes(String iface) { List<RouteInfo> routes = new ArrayList<RouteInfo>(3); if (ipAddress != null) { @@ -107,6 +148,7 @@ public class StaticIpConfiguration implements Parcelable { * contained in the LinkProperties will not be a complete picture of the link's configuration, * because any configuration information that is obtained dynamically by the network (e.g., * IPv6 configuration) will not be included. + * @hide */ public LinkProperties toLinkProperties(String iface) { LinkProperties lp = new LinkProperties(); @@ -124,6 +166,7 @@ public class StaticIpConfiguration implements Parcelable { return lp; } + @Override public String toString() { StringBuffer str = new StringBuffer(); @@ -143,6 +186,7 @@ public class StaticIpConfiguration implements Parcelable { return str.toString(); } + @Override public int hashCode() { int result = 13; result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode()); @@ -168,12 +212,10 @@ public class StaticIpConfiguration implements Parcelable { } /** Implement the Parcelable interface */ - public static Creator<StaticIpConfiguration> CREATOR = + public static final Creator<StaticIpConfiguration> CREATOR = new Creator<StaticIpConfiguration>() { public StaticIpConfiguration createFromParcel(Parcel in) { - StaticIpConfiguration s = new StaticIpConfiguration(); - readFromParcel(s, in); - return s; + return readFromParcel(in); } public StaticIpConfiguration[] newArray(int size) { @@ -182,29 +224,34 @@ public class StaticIpConfiguration implements Parcelable { }; /** Implement the Parcelable interface */ + @Override public int describeContents() { return 0; } /** Implement the Parcelable interface */ + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(ipAddress, flags); - NetworkUtils.parcelInetAddress(dest, gateway, flags); + InetAddressUtils.parcelInetAddress(dest, gateway, flags); dest.writeInt(dnsServers.size()); for (InetAddress dnsServer : dnsServers) { - NetworkUtils.parcelInetAddress(dest, dnsServer, flags); + InetAddressUtils.parcelInetAddress(dest, dnsServer, flags); } dest.writeString(domains); } - protected static void readFromParcel(StaticIpConfiguration s, Parcel in) { + /** @hide */ + public static StaticIpConfiguration readFromParcel(Parcel in) { + final StaticIpConfiguration s = new StaticIpConfiguration(); s.ipAddress = in.readParcelable(null); - s.gateway = NetworkUtils.unparcelInetAddress(in); + s.gateway = InetAddressUtils.unparcelInetAddress(in); s.dnsServers.clear(); int size = in.readInt(); for (int i = 0; i < size; i++) { - s.dnsServers.add(NetworkUtils.unparcelInetAddress(in)); + s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in)); } s.domains = in.readString(); + return s; } } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bbf8f97c8865..49c6f74b1a34 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -128,10 +128,14 @@ public class TrafficStats { public static final int TAG_SYSTEM_APP = 0xFFFFFF05; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; /** @hide */ public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; /** @hide */ public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; @@ -140,6 +144,8 @@ public class TrafficStats { /** @hide */ public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index dc099a46aa2a..784f23311103 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -791,6 +791,27 @@ public class VpnService extends Service { } /** + * Marks the VPN network as metered. A VPN network is classified as metered when the user is + * sensitive to heavy data usage due to monetary costs and/or data limitations. In such + * cases, you should set this to {@code true} so that apps on the system can avoid doing + * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN + * network to inherit its meteredness from its underlying networks. + * + * <p>VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be + * considered metered by default. + * + * @param isMetered {@code true} if VPN network should be treated as metered regardless of + * underlying network meteredness + * @return this {@link Builder} object to facilitate chaining method calls + * @see #setUnderlyingNetworks(Networks[]) + * @see ConnectivityManager#isActiveNetworkMetered() + */ + public Builder setMetered(boolean isMetered) { + mConfig.isMetered = isMetered; + return this; + } + + /** * Create a VPN interface using the parameters supplied to this * builder. The interface works on IP packets, and a file descriptor * is returned for the application to access them. Each read diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java index f28cdc902848..e09fa8fd9e77 100644 --- a/core/java/android/net/apf/ApfCapabilities.java +++ b/core/java/android/net/apf/ApfCapabilities.java @@ -16,11 +16,19 @@ package android.net.apf; +import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.content.Context; + +import com.android.internal.R; + /** * APF program support capabilities. * * @hide */ +@SystemApi +@TestApi public class ApfCapabilities { /** * Version of APF instruction set supported for packet filtering. 0 indicates no support for @@ -69,4 +77,18 @@ public class ApfCapabilities { public boolean hasDataAccess() { return apfVersionSupported >= 4; } + + /** + * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. + */ + public static boolean getApfDrop8023Frames(Context context) { + return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); + } + + /** + * @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped. + */ + public static int[] getApfEthTypeBlackList(Context context) { + return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList); + } } diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java index 1634694cc71f..7432687e136f 100644 --- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java +++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java @@ -17,11 +17,15 @@ package android.net.captiveportal; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; /** * Result of calling isCaptivePortal(). * @hide */ +@SystemApi +@TestApi public final class CaptivePortalProbeResult { public static final int SUCCESS_CODE = 204; public static final int FAILED_CODE = 599; diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java index 57a926afec54..7ad4ecf2264c 100644 --- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java +++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java @@ -21,21 +21,26 @@ import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; /** @hide */ +@SystemApi +@TestApi public abstract class CaptivePortalProbeSpec { - public static final String HTTP_LOCATION_HEADER_NAME = "Location"; - private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName(); private static final String REGEX_SEPARATOR = "@@/@@"; private static final String SPEC_SEPARATOR = "@@,@@"; @@ -55,7 +60,9 @@ public abstract class CaptivePortalProbeSpec { * @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}. * @throws ParseException The string is empty, does not match the above format, or a regular * expression is invalid for {@link Pattern#compile(String)}. + * @hide */ + @VisibleForTesting @NonNull public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException, MalformedURLException { @@ -113,7 +120,8 @@ public abstract class CaptivePortalProbeSpec { * <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}. * <p>This method does not throw but ignores any entry that could not be parsed. */ - public static CaptivePortalProbeSpec[] parseCaptivePortalProbeSpecs(String settingsVal) { + public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs( + String settingsVal) { List<CaptivePortalProbeSpec> specs = new ArrayList<>(); if (settingsVal != null) { for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) { @@ -128,7 +136,7 @@ public abstract class CaptivePortalProbeSpec { if (specs.isEmpty()) { Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal)); } - return specs.toArray(new CaptivePortalProbeSpec[specs.size()]); + return specs; } /** diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java index 2a942eedcb47..3008115e063b 100644 --- a/core/java/android/net/metrics/DhcpClientEvent.java +++ b/core/java/android/net/metrics/DhcpClientEvent.java @@ -31,10 +31,6 @@ import android.os.Parcelable; public final class DhcpClientEvent implements IpConnectivityLog.Event { // Names for recording DhcpClient pseudo-state transitions. - /** {@hide} Represents transitions from DhcpInitState to DhcpBoundState */ - public static final String INITIAL_BOUND = "InitialBoundState"; - /** {@hide} Represents transitions from and to DhcpBoundState via DhcpRenewingState */ - public static final String RENEWING_BOUND = "RenewingBoundState"; /** @hide */ public final String msg; diff --git a/packages/NetworkStack/src/android/net/util/FdEventsReader.java b/core/java/android/net/shared/FdEventsReader.java index 8bbf449f6374..bffbfb115886 100644 --- a/packages/NetworkStack/src/android/net/util/FdEventsReader.java +++ b/core/java/android/net/shared/FdEventsReader.java @@ -14,22 +14,22 @@ * limitations under the License. */ -package android.net.util; +package android.net.shared; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import android.annotation.NonNull; import android.annotation.Nullable; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.system.ErrnoException; import android.system.OsConstants; -import libcore.io.IoUtils; - import java.io.FileDescriptor; +import java.io.IOException; /** @@ -63,6 +63,7 @@ import java.io.FileDescriptor; * All public methods MUST only be called from the same thread with which * the Handler constructor argument is associated. * + * @param <BufferType> the type of the buffer used to read data. * @hide */ public abstract class FdEventsReader<BufferType> { @@ -80,7 +81,10 @@ public abstract class FdEventsReader<BufferType> { private long mPacketsReceived; protected static void closeFd(FileDescriptor fd) { - IoUtils.closeQuietly(fd); + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } } protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) { @@ -89,6 +93,7 @@ public abstract class FdEventsReader<BufferType> { mBuffer = buffer; } + /** Start this FdEventsReader. */ public void start() { if (onCorrectThread()) { createAndRegisterFd(); @@ -100,6 +105,7 @@ public abstract class FdEventsReader<BufferType> { } } + /** Stop this FdEventsReader and destroy the file descriptor. */ public void stop() { if (onCorrectThread()) { unregisterAndDestroyFd(); @@ -112,22 +118,29 @@ public abstract class FdEventsReader<BufferType> { } @NonNull - public Handler getHandler() { return mHandler; } + public Handler getHandler() { + return mHandler; + } protected abstract int recvBufSize(@NonNull BufferType buffer); - public int recvBufSize() { return recvBufSize(mBuffer); } + /** Returns the size of the receive buffer. */ + public int recvBufSize() { + return recvBufSize(mBuffer); + } /** * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}. * * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0. */ - public final long numPacketsReceived() { return mPacketsReceived; } + public final long numPacketsReceived() { + return mPacketsReceived; + } /** - * Subclasses MUST create the listening socket here, including setting - * all desired socket options, interface or address/port binding, etc. + * Subclasses MUST create the listening socket here, including setting all desired socket + * options, interface or address/port binding, etc. The socket MUST be created nonblocking. */ @Nullable protected abstract FileDescriptor createFd(); @@ -171,10 +184,6 @@ public abstract class FdEventsReader<BufferType> { try { mFd = createFd(); - if (mFd != null) { - // Force the socket to be non-blocking. - IoUtils.setBlocking(mFd, false); - } } catch (Exception e) { logError("Failed to create socket: ", e); closeFd(mFd); @@ -199,7 +208,9 @@ public abstract class FdEventsReader<BufferType> { onStart(); } - private boolean isRunning() { return (mFd != null) && mFd.valid(); } + private boolean isRunning() { + return (mFd != null) && mFd.valid(); + } // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. private boolean handleInput() { diff --git a/core/java/android/net/shared/Inet4AddressUtils.java b/core/java/android/net/shared/Inet4AddressUtils.java new file mode 100644 index 000000000000..bec0c84fa689 --- /dev/null +++ b/core/java/android/net/shared/Inet4AddressUtils.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.shared; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to work with IPv4 addresses. + * @hide + */ +public class Inet4AddressUtils { + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4) + * + * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes, + * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead. + * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is + * lower-order IPv4 address byte + */ + public static Inet4Address intToInet4AddressHTL(int hostAddress) { + return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); + } + + /** + * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) + * @param hostAddress an int coding for an IPv4 address + */ + public static Inet4Address intToInet4AddressHTH(int hostAddress) { + byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), + (byte) (0xff & (hostAddress >> 16)), + (byte) (0xff & (hostAddress >> 8)), + (byte) (0xff & hostAddress) }; + + try { + return (Inet4Address) InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + throw new AssertionError(); + } + } + + /** + * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304) + * + * <p>This conversion can help order IP addresses: considering the ordering + * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned + * integers with {@link Integer#toUnsignedLong}. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTH(Inet4Address inetAddr) + throws IllegalArgumentException { + byte [] addr = inetAddr.getAddress(); + return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16) + | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff); + } + + /** + * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201) + * + * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead. + * @param inetAddr is an InetAddress corresponding to the IPv4 address + * @return the IP address as integer + */ + public static int inet4AddressToIntHTL(Inet4Address inetAddr) { + return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr)); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000) + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTH(int prefixLength) + throws IllegalArgumentException { + if (prefixLength < 0 || prefixLength > 32) { + throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); + } + // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1) + return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength); + } + + /** + * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff). + * + * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes, + * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead. + * @return the IPv4 netmask as an integer + */ + public static int prefixLengthToV4NetmaskIntHTL(int prefixLength) + throws IllegalArgumentException { + return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } + + /** + * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous. + * @param netmask as a {@code Inet4Address}. + * @return the network prefix length + * @throws IllegalArgumentException the specified netmask was not contiguous. + * @hide + */ + public static int netmaskToPrefixLength(Inet4Address netmask) { + // inetAddressToInt returns an int in *network* byte order. + int i = inet4AddressToIntHTH(netmask); + int prefixLength = Integer.bitCount(i); + int trailingZeros = Integer.numberOfTrailingZeros(i); + if (trailingZeros != 32 - prefixLength) { + throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); + } + return prefixLength; + } + + /** + * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. + */ + public static int getImplicitNetmask(Inet4Address address) { + int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. + if (firstByte < 128) { + return 8; + } else if (firstByte < 192) { + return 16; + } else if (firstByte < 224) { + return 24; + } else { + return 32; // Will likely not end well for other reasons. + } + } + + /** + * Get the broadcast address for a given prefix. + * + * <p>For example 192.168.0.1/24 -> 192.168.0.255 + */ + public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) + throws IllegalArgumentException { + final int intBroadcastAddr = inet4AddressToIntHTH(addr) + | ~prefixLengthToV4NetmaskIntHTH(prefixLength); + return intToInet4AddressHTH(intBroadcastAddr); + } + + /** + * Get a prefix mask as Inet4Address for a given prefix length. + * + * <p>For example 20 -> 255.255.240.0 + */ + public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) + throws IllegalArgumentException { + return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); + } +} diff --git a/core/java/android/net/shared/InetAddressUtils.java b/core/java/android/net/shared/InetAddressUtils.java new file mode 100644 index 000000000000..c9ee3a7cce4b --- /dev/null +++ b/core/java/android/net/shared/InetAddressUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.shared; + +import android.os.Parcel; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Collection of utilities to interact with {@link InetAddress} + * @hide + */ +public class InetAddressUtils { + + /** + * Writes an InetAddress to a parcel. The address may be null. This is likely faster than + * calling writeSerializable. + * @hide + */ + public static void parcelInetAddress(Parcel parcel, InetAddress address, int flags) { + byte[] addressArray = (address != null) ? address.getAddress() : null; + parcel.writeByteArray(addressArray); + } + + /** + * Reads an InetAddress from a parcel. Returns null if the address that was written was null + * or if the data is invalid. + * @hide + */ + public static InetAddress unparcelInetAddress(Parcel in) { + byte[] addressArray = in.createByteArray(); + if (addressArray == null) { + return null; + } + try { + return InetAddress.getByAddress(addressArray); + } catch (UnknownHostException e) { + return null; + } + } + + private InetAddressUtils() {} +} diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java index de67cf5952f4..fbb15ed693d9 100644 --- a/core/java/android/net/util/SocketUtils.java +++ b/core/java/android/net/util/SocketUtils.java @@ -20,20 +20,29 @@ import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_BINDTODEVICE; import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.net.MacAddress; import android.net.NetworkUtils; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.PacketSocketAddress; +import android.system.StructTimeval; + +import libcore.io.IoBridge; import java.io.FileDescriptor; +import java.io.IOException; +import java.net.Inet4Address; import java.net.SocketAddress; +import java.net.SocketException; /** * Collection of utilities to interact with raw sockets. * @hide */ @SystemApi +@TestApi public class SocketUtils { /** * Create a raw datagram socket that is bound to an interface. @@ -57,18 +66,94 @@ public class SocketUtils { } /** - * Make a socket address to bind to packet sockets. + * Make socket address that packet sockets can bind to. */ public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) { return new PacketSocketAddress(protocol, ifIndex); } /** - * Make a socket address to send raw packets. + * Make a socket address that packet socket can send packets to. */ public static SocketAddress makePacketSocketAddress(int ifIndex, byte[] hwAddr) { return new PacketSocketAddress(ifIndex, hwAddr); } + /** + * Set an option on a socket that takes a time value argument. + */ + public static void setSocketTimeValueOption( + FileDescriptor fd, int level, int option, long millis) throws ErrnoException { + Os.setsockoptTimeval(fd, level, option, StructTimeval.fromMillis(millis)); + } + + /** + * Bind a socket to the specified address. + */ + public static void bindSocket(FileDescriptor fd, SocketAddress addr) + throws ErrnoException, SocketException { + Os.bind(fd, addr); + } + + /** + * Connect a socket to the specified address. + */ + public static void connectSocket(FileDescriptor fd, SocketAddress addr) + throws ErrnoException, SocketException { + Os.connect(fd, addr); + } + + /** + * Send a message on a socket, using the specified SocketAddress. + */ + public static void sendTo(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, + int flags, SocketAddress addr) throws ErrnoException, SocketException { + Os.sendto(fd, bytes, byteOffset, byteCount, flags, addr); + } + + /** + * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor) + */ + public static void closeSocket(FileDescriptor fd) throws IOException { + IoBridge.closeAndSignalBlockedThreads(fd); + } + + /** + * Attaches a socket filter that accepts DHCP packets to the given socket. + */ + public static void attachDhcpFilter(FileDescriptor fd) throws SocketException { + NetworkUtils.attachDhcpFilter(fd); + } + + /** + * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket. + * @param fd the socket's {@link FileDescriptor}. + * @param packetType the hardware address type, one of ARPHRD_*. + */ + public static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException { + NetworkUtils.attachRaFilter(fd, packetType); + } + + /** + * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity. + * + * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges. + * + * @param fd the socket's {@link FileDescriptor}. + * @param packetType the hardware address type, one of ARPHRD_*. + */ + public static void attachControlPacketFilter(FileDescriptor fd, int packetType) + throws SocketException { + NetworkUtils.attachControlPacketFilter(fd, packetType); + } + + /** + * Add an entry into the ARP cache. + */ + public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname, + FileDescriptor fd) throws IOException { + NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd); + } + private SocketUtils() {} } diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 6801618e6a68..0b2cfdd9ece3 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -68,4 +68,8 @@ interface INfcAdapter void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler); void verifyNfcPermission(); + boolean isNfcSecureEnabled(); + boolean deviceSupportsNfcSecure(); + boolean setNfcSecure(boolean enable); + } diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index e55e0364f5d4..a7d2ee98b45c 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -1702,6 +1702,63 @@ public final class NfcAdapter { } /** + * Sets Secure NFC feature. + * <p>This API is for the Settings application. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean setNfcSecure(boolean enable) { + if (!sHasNfcFeature) { + throw new UnsupportedOperationException(); + } + try { + return sService.setNfcSecure(enable); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return false; + } + } + + /** + * Checks if the device supports Secure NFC functionality. + * + * @return True if device supports Secure NFC, false otherwise + * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + */ + public boolean deviceSupportsNfcSecure() { + if (!sHasNfcFeature) { + throw new UnsupportedOperationException(); + } + try { + return sService.deviceSupportsNfcSecure(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return false; + } + } + + /** + * Checks Secure NFC feature is enabled. + * + * @return True if device supports Secure NFC is enabled, false otherwise + * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @throws UnsupportedOperationException if device doesn't support + * Secure NFC functionality. {@link #deviceSupportsNfcSecure} + */ + public boolean isNfcSecureEnabled() { + if (!sHasNfcFeature) { + throw new UnsupportedOperationException(); + } + try { + return sService.isNfcSecureEnabled(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + return false; + } + } + + /** * Enable NDEF Push feature. * <p>This API is for the Settings application. * @hide diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index d463b4422847..3a5b8a86204e 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -16,10 +16,12 @@ package android.os; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.IBinder.DeathRecipient; @@ -27,14 +29,14 @@ import android.os.IBinder.DeathRecipient; import java.io.FileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * Class that provides a privileged API to capture and consume bugreports. * * @hide */ -// TODO: Expose API when the implementation is more complete. -// @SystemApi +@SystemApi @SystemService(Context.BUGREPORT_SERVICE) public class BugreportManager { private final Context mContext; @@ -47,47 +49,46 @@ public class BugreportManager { } /** - * An interface describing the listener for bugreport progress and status. + * An interface describing the callback for bugreport progress and status. */ - public interface BugreportListener { - /** - * Called when there is a progress update. - * @param progress the progress in [0.0, 100.0] - */ - void onProgress(float progress); - + public abstract static class BugreportCallback { + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = { BUGREPORT_ERROR_INVALID_INPUT, - BUGREPORT_ERROR_RUNTIME + BUGREPORT_ERROR_RUNTIME, + BUGREPORT_ERROR_USER_DENIED_CONSENT, + BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT }) /** Possible error codes taking a bugreport can encounter */ - @interface BugreportErrorCode {} + public @interface BugreportErrorCode {} /** The input options were invalid */ - int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT; + public static final int BUGREPORT_ERROR_INVALID_INPUT = + IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT; /** A runtime error occured */ - int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR; + public static final int BUGREPORT_ERROR_RUNTIME = + IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR; /** User denied consent to share the bugreport */ - int BUGREPORT_ERROR_USER_DENIED_CONSENT = + public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT; /** The request to get user consent timed out. */ - int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = + public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = IDumpstateListener.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT; /** + * Called when there is a progress update. + * @param progress the progress in [0.0, 100.0] + */ + public void onProgress(float progress) {} + + /** * Called when taking bugreport resulted in an error. * - * @param errorCode the error that occurred. Possible values are - * {@code BUGREPORT_ERROR_INVALID_INPUT}, - * {@code BUGREPORT_ERROR_RUNTIME}, - * {@code BUGREPORT_ERROR_USER_DENIED_CONSENT}, - * {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT}. - * * <p>If {@code BUGREPORT_ERROR_USER_DENIED_CONSENT} is passed, then the user did not * consent to sharing the bugreport with the calling app. * @@ -95,19 +96,19 @@ public class BugreportManager { * out, but the bugreport could be available in the internal directory of dumpstate for * manual retrieval. */ - void onError(@BugreportErrorCode int errorCode); + public void onError(@BugreportErrorCode int errorCode) {} /** * Called when taking bugreport finishes successfully. */ - void onFinished(); + public void onFinished() {} } /** * Starts a bugreport. * * <p>This starts a bugreport in the background. However the call itself can take several - * seconds to return in the worst case. {@code listener} will receive progress and status + * seconds to return in the worst case. {@code callback} will receive progress and status * updates. * * <p>The bugreport artifacts will be copied over to the given file descriptors only if the @@ -118,19 +119,23 @@ public class BugreportManager { * @param screenshotFd file to write the screenshot, if necessary. This should be opened * in write-only, append mode. * @param params options that specify what kind of a bugreport should be taken - * @param listener callback for progress and status updates + * @param callback callback for progress and status updates */ @RequiresPermission(android.Manifest.permission.DUMP) - public void startBugreport(@NonNull FileDescriptor bugreportFd, - @Nullable FileDescriptor screenshotFd, - @NonNull BugreportParams params, @NonNull BugreportListener listener) { + public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd, + @Nullable ParcelFileDescriptor screenshotFd, + @NonNull BugreportParams params, + @NonNull @CallbackExecutor Executor executor, + @NonNull BugreportCallback callback) { // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary. - DumpstateListener dsListener = new DumpstateListener(listener); - + DumpstateListener dsListener = new DumpstateListener(executor, callback); try { // Note: mBinder can get callingUid from the binder transaction. mBinder.startBugreport(-1 /* callingUid */, - mContext.getOpPackageName(), bugreportFd, screenshotFd, + mContext.getOpPackageName(), + (bugreportFd != null ? bugreportFd.getFileDescriptor() : new FileDescriptor()), + (screenshotFd != null + ? screenshotFd.getFileDescriptor() : new FileDescriptor()), params.getMode(), dsListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -151,10 +156,12 @@ public class BugreportManager { private final class DumpstateListener extends IDumpstateListener.Stub implements DeathRecipient { - private final BugreportListener mListener; + private final Executor mExecutor; + private final BugreportCallback mCallback; - DumpstateListener(@Nullable BugreportListener listener) { - mListener = listener; + DumpstateListener(Executor executor, @Nullable BugreportCallback callback) { + mExecutor = executor; + mCallback = callback; } @Override @@ -164,19 +171,37 @@ public class BugreportManager { @Override public void onProgress(int progress) throws RemoteException { - mListener.onProgress(progress); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mCallback.onProgress(progress); + }); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(int errorCode) throws RemoteException { - mListener.onError(errorCode); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> { + mCallback.onError(errorCode); + }); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onFinished() throws RemoteException { + final long identity = Binder.clearCallingIdentity(); try { - mListener.onFinished(); + mExecutor.execute(() -> { + mCallback.onFinished(); + }); } finally { + Binder.restoreCallingIdentity(identity); // The bugreport has finished. Let's shutdown the service to minimize its footprint. cancelBugreport(); } diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java index 4e696aed1fa8..3871375cfced 100644 --- a/core/java/android/os/BugreportParams.java +++ b/core/java/android/os/BugreportParams.java @@ -17,6 +17,7 @@ package android.os; import android.annotation.IntDef; +import android.annotation.SystemApi; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -26,8 +27,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -// TODO: Expose API when the implementation is more complete. -// @SystemApi +@SystemApi public final class BugreportParams { private final int mMode; diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java deleted file mode 100644 index 53037b2499cd..000000000000 --- a/core/java/android/os/DumpstateOptions.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -/** - * Options passed to dumpstate service. - * - * @hide - */ -public final class DumpstateOptions implements Parcelable { - // If true the caller can get callbacks with per-section - // progress details. - private final boolean mGetSectionDetails; - // Name of the caller. - private final String mName; - - public DumpstateOptions(Parcel in) { - mGetSectionDetails = in.readBoolean(); - mName = in.readString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeBoolean(mGetSectionDetails); - out.writeString(mName); - } - - public static final Parcelable.Creator<DumpstateOptions> CREATOR = - new Parcelable.Creator<DumpstateOptions>() { - public DumpstateOptions createFromParcel(Parcel in) { - return new DumpstateOptions(in); - } - - public DumpstateOptions[] newArray(int size) { - return new DumpstateOptions[size]; - } - }; -} diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS new file mode 100644 index 000000000000..b568f157c01d --- /dev/null +++ b/core/java/android/os/OWNERS @@ -0,0 +1,2 @@ +# Zygote +per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/java/android/os/ParcelUuid.java b/core/java/android/os/ParcelUuid.java index 2c68ddd431ca..5b45ac231d70 100644 --- a/core/java/android/os/ParcelUuid.java +++ b/core/java/android/os/ParcelUuid.java @@ -16,6 +16,8 @@ package android.os; +import android.annotation.UnsupportedAppUsage; + import java.util.UUID; /** @@ -109,6 +111,7 @@ public final class ParcelUuid implements Parcelable { public static final Parcelable.Creator<ParcelUuid> CREATOR = new Parcelable.Creator<ParcelUuid>() { + @UnsupportedAppUsage public ParcelUuid createFromParcel(Parcel source) { long mostSigBits = source.readLong(); long leastSigBits = source.readLong(); diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index 94441cae7567..a96618a92cc6 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.UnsupportedAppUsage; import android.util.Slog; import java.io.File; @@ -69,6 +70,7 @@ public class SELinux { * @param path the pathname of the file object. * @return a security context given as a String. */ + @UnsupportedAppUsage public static final native String getFileContext(String path); /** diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 648c022d8673..de41ce2e08c5 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -226,6 +226,7 @@ public final class UserHandle implements Parcelable { * @hide */ @TestApi + @SystemApi public static @AppIdInt int getAppId(int uid) { return uid % PER_USER_RANGE; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bbd76d2a1f12..e904b0713e24 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5671,6 +5671,16 @@ public final class Settings { public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown"; /** + * Comma separated list of packages that are allowed to access the network when VPN is in + * lockdown mode but not running. + * @see #ALWAYS_ON_VPN_LOCKDOWN + * + * @hide + */ + public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST = + "always_on_vpn_lockdown_whitelist"; + + /** * Whether applications can be installed for this user via the system's * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism. * diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS index 3c9bbf8797ea..426f002ad236 100644 --- a/core/java/android/service/dreams/OWNERS +++ b/core/java/android/service/dreams/OWNERS @@ -1,3 +1,3 @@ -dsandler@google.com +dsandler@android.com michaelwr@google.com roosa@google.com diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index f2259b045c0a..2ee72bffc9ec 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -20,6 +20,7 @@ import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; @@ -389,9 +390,13 @@ public abstract class LayoutInflater { } private void initPrecompiledViews() { + initPrecompiledViews( + SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false)); + } + + private void initPrecompiledViews(boolean enablePrecompiledViews) { + mUseCompiledView = enablePrecompiledViews; try { - mUseCompiledView = - SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false); if (mUseCompiledView) { mPrecompiledClassLoader = mContext.getClassLoader(); String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME; @@ -409,6 +414,17 @@ public abstract class LayoutInflater { } mUseCompiledView = false; } + if (!mUseCompiledView) { + mPrecompiledClassLoader = null; + } + } + + /** + * @hide for use by CTS tests + */ + @TestApi + public void setPrecompiledLayoutsEnabledForTesting(boolean enablePrecompiledLayouts) { + initPrecompiledViews(enablePrecompiledLayouts); } /** diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java index da8605e645b4..65b974ba8b42 100644 --- a/core/java/com/android/internal/net/VpnConfig.java +++ b/core/java/com/android/internal/net/VpnConfig.java @@ -104,6 +104,7 @@ public class VpnConfig implements Parcelable { public boolean allowBypass; public boolean allowIPv4; public boolean allowIPv6; + public boolean isMetered = true; public Network[] underlyingNetworks; public ProxyInfo proxyInfo; @@ -165,6 +166,7 @@ public class VpnConfig implements Parcelable { out.writeInt(allowBypass ? 1 : 0); out.writeInt(allowIPv4 ? 1 : 0); out.writeInt(allowIPv6 ? 1 : 0); + out.writeInt(isMetered ? 1 : 0); out.writeTypedArray(underlyingNetworks, flags); out.writeParcelable(proxyInfo, flags); } @@ -191,6 +193,7 @@ public class VpnConfig implements Parcelable { config.allowBypass = in.readInt() != 0; config.allowIPv4 = in.readInt() != 0; config.allowIPv6 = in.readInt() != 0; + config.isMetered = in.readInt() != 0; config.underlyingNetworks = in.createTypedArray(Network.CREATOR); config.proxyInfo = in.readParcelable(null); return config; diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS new file mode 100644 index 000000000000..928310549e6e --- /dev/null +++ b/core/java/com/android/internal/os/OWNERS @@ -0,0 +1 @@ +per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 3859b951ed45..1048cb4e6e3a 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -120,8 +120,6 @@ public final class Zygote { * */ protected static FileDescriptor sBlastulaPoolEventFD; - private static final ZygoteHooks VM_HOOKS = new ZygoteHooks(); - /** * An extraArg passed when a zygote process is forking a child-zygote, specifying a name * in the abstract socket namespace. This socket name is what the new child zygote @@ -213,7 +211,7 @@ public final class Zygote { public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { - VM_HOOKS.preFork(); + ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( @@ -226,7 +224,7 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } - VM_HOOKS.postForkCommon(); + ZygoteHooks.postForkCommon(); return pid; } @@ -275,7 +273,7 @@ public final class Zygote { * * TODO (chriswailes): Look into moving this to immediately after the fork. */ - VM_HOOKS.postForkCommon(); + ZygoteHooks.postForkCommon(); } private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids, @@ -312,7 +310,7 @@ public final class Zygote { */ public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { - VM_HOOKS.preFork(); + ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkSystemServer( @@ -322,7 +320,7 @@ public final class Zygote { if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); } - VM_HOOKS.postForkCommon(); + ZygoteHooks.postForkCommon(); return pid; } @@ -390,7 +388,7 @@ public final class Zygote { // Disable some VM functionality and reset some system values // before forking. - VM_HOOKS.preFork(); + ZygoteHooks.preFork(); resetNicePriority(); while (blastulaPoolCount++ < sBlastulaPoolMax) { @@ -403,7 +401,7 @@ public final class Zygote { // Re-enable runtime services for the Zygote. Blastula services // are re-enabled in specializeBlastula. - VM_HOOKS.postForkCommon(); + ZygoteHooks.postForkCommon(); Log.i("zygote", "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn); } @@ -817,12 +815,12 @@ public final class Zygote { private static void callPostForkSystemServerHooks() { // SystemServer specific post fork hooks run before child post fork hooks. - VM_HOOKS.postForkSystemServer(); + ZygoteHooks.postForkSystemServer(); } private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet) { - VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); + ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); } /** diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index ab356a6f9a99..2bb075989f35 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -26,6 +26,7 @@ import static android.system.OsConstants.STDOUT_FILENO; import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS; import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; +import android.metrics.LogMaker; import android.net.Credentials; import android.net.LocalSocket; import android.os.Process; @@ -35,6 +36,9 @@ import android.system.Os; import android.system.StructPollfd; import android.util.Log; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -311,9 +315,43 @@ class ZygoteConnection { } } - private void handleHiddenApiAccessLogSampleRate(int percent) { + private class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger { + + private final MetricsLogger mMetricsLogger = new MetricsLogger(); + + public void hiddenApiUsed(String packageName, String signature, + int accessMethod, boolean accessDenied) { + int accessMethodMetric = HiddenApiUsageLogger.ACCESS_METHOD_NONE; + switch(accessMethod) { + case HiddenApiUsageLogger.ACCESS_METHOD_NONE: + accessMethodMetric = MetricsEvent.ACCESS_METHOD_NONE; + break; + case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION: + accessMethodMetric = MetricsEvent.ACCESS_METHOD_REFLECTION; + break; + case HiddenApiUsageLogger.ACCESS_METHOD_JNI: + accessMethodMetric = MetricsEvent.ACCESS_METHOD_JNI; + break; + case HiddenApiUsageLogger.ACCESS_METHOD_LINKING: + accessMethodMetric = MetricsEvent.ACCESS_METHOD_LINKING; + break; + } + LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_HIDDEN_API_ACCESSED) + .setPackageName(packageName) + .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_SIGNATURE, signature) + .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_METHOD, + accessMethodMetric); + if (accessDenied) { + logMaker.addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_DENIED, 1); + } + mMetricsLogger.write(logMaker); + } + } + + private void handleHiddenApiAccessLogSampleRate(int samplingRate) { try { - ZygoteInit.setHiddenApiAccessLogSampleRate(percent); + ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate); + ZygoteInit.setHiddenApiUsageLogger(new HiddenApiUsageLogger()); mSocketOutStream.writeInt(0); } catch (IOException ioe) { throw new IllegalStateException("Error writing to command socket", ioe); diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index e3e55ed28c6f..9f23797d6ccc 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -533,6 +533,14 @@ public class ZygoteInit { } /** + * Sets the implementation to be used for logging hidden API accesses + * @param logger the implementation of the VMRuntime.HiddenApiUsageLogger interface + */ + public static void setHiddenApiUsageLogger(VMRuntime.HiddenApiUsageLogger logger) { + VMRuntime.getRuntime().setHiddenApiUsageLogger(logger); + } + + /** * Creates a PathClassLoader for the given class path that is associated with a shared * namespace, i.e., this classloader can access platform-private native libraries. The * classloader will use java.library.path as the native library path. diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index e5ad1f47d37d..7398e9526a42 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -16,6 +16,7 @@ package com.android.internal.util; +import android.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -1354,6 +1355,7 @@ public class StateMachine { * Add a new state to the state machine, parent will be null * @param state to add */ + @UnsupportedAppUsage public final void addState(State state) { mSmHandler.addState(state, null); } @@ -1372,6 +1374,7 @@ public class StateMachine { * * @param initialState is the state which will receive the first message. */ + @UnsupportedAppUsage public final void setInitialState(State initialState) { mSmHandler.setInitialState(initialState); } @@ -1410,6 +1413,7 @@ public class StateMachine { * * @param destState will be the state that receives the next message. */ + @UnsupportedAppUsage public final void transitionTo(IState destState) { mSmHandler.transitionTo(destState); } @@ -2053,6 +2057,7 @@ public class StateMachine { /** * Start the state machine. */ + @UnsupportedAppUsage public void start() { // mSmHandler can be null if the state machine has quit. SmHandler smh = mSmHandler; diff --git a/core/jni/OWNERS b/core/jni/OWNERS index a365a566f038..86342c47c455 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -4,3 +4,6 @@ per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhij # Connectivity per-file android_net_* = ek@google.com, lorenzo@google.com, satk@google.com + +# Zygote +per-file com_android_inernal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 03a463e9b55c..e344f2a83838 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -551,7 +551,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi // if we only close the file descriptor and not the file object it is used to // create. If we don't explicitly clean up the file (which in turn closes the // descriptor) the buffers allocated internally by fseek will be leaked. - int dupDescriptor = dup(descriptor); + int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0); FILE* file = fdopen(dupDescriptor, "r"); if (file == NULL) { diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp index df735ae12feb..42f1a62d5abd 100644 --- a/core/jni/android/graphics/ImageDecoder.cpp +++ b/core/jni/android/graphics/ImageDecoder.cpp @@ -132,7 +132,7 @@ static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/, "broken file descriptor; fstat returned -1", nullptr, source); } - int dupDescriptor = dup(descriptor); + int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0); FILE* file = fdopen(dupDescriptor, "r"); if (file == NULL) { close(dupDescriptor); diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index 7738d849be39..f40b461a6dfd 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -72,7 +72,7 @@ static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descri return 0; } - unique_fd dup_fd(::dup(fd)); + unique_fd dup_fd(::fcntl(fd, F_DUPFD_CLOEXEC, 0)); if (dup_fd < 0) { jniThrowIOException(env, errno); return 0; diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index 2f25d8f2d3a4..e22f581e14e2 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -54,7 +54,7 @@ struct Header { namespace android { static void ReadFile(const char* path, String8& s) { - int fd = open(path, O_RDONLY); + int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd != -1) { char bytes[1024]; ssize_t byteCount; diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp index 190ddced7312..3ff24468e3aa 100644 --- a/core/jni/android_hardware_SerialPort.cpp +++ b/core/jni/android_hardware_SerialPort.cpp @@ -134,7 +134,7 @@ android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescript int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy - fd = dup(fd); + fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); if (fd < 0) { jniThrowException(env, "java/io/IOException", "Could not open serial port"); return; diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index d953aee6b753..b885c285e380 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -49,7 +49,7 @@ android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring dev { int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy - fd = dup(fd); + fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); if (fd < 0) return JNI_FALSE; diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 8df028a6af65..8be617f08ac3 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -943,7 +943,7 @@ static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp) } /* dup() the descriptor so we don't close the original with fclose() */ - int fd = dup(origFd); + int fd = fcntl(origFd, F_DUPFD_CLOEXEC, 0); if (fd < 0) { ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno)); jniThrowRuntimeException(env, "dup() failed"); diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index e64d2afe7bf3..ee11b6162db0 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -96,7 +96,7 @@ static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass) return toJavaStringArray(env, cStrings); } -static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckFlags::Type checks) { +static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) { std::vector<std::string> cPackageInfo; if (packageInfo) { size_t count = env->GetArrayLength(packageInfo); @@ -109,18 +109,19 @@ static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckF } } std::string error; - int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error, checks); + int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error); if (status) LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error; return status; } -static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) { - return verify(env, packageInfo, ::android::vintf::CheckFlags::ENABLE_ALL_CHECKS); -} - static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) { - return verify(env, nullptr, ::android::vintf::CheckFlags::DISABLE_AVB_CHECK); + std::string error; + int32_t status = VintfObject::CheckCompatibility({}, &error, + ::android::vintf::CheckFlags::DISABLE_AVB_CHECK); + if (status) + LOG(WARNING) << "VintfObject.verifyWithoutAvb() returns " << status << ": " << error; + return status; } static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) { diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp index 6f9cc22fb3ab..de307737493e 100644 --- a/core/jni/android_text_Hyphenator.cpp +++ b/core/jni/android_text_Hyphenator.cpp @@ -37,7 +37,7 @@ static std::string buildFileName(const std::string& locale) { static const uint8_t* mmapPatternFile(const std::string& locale) { const std::string hyFilePath = buildFileName(locale); - const int fd = open(hyFilePath.c_str(), O_RDONLY); + const int fd = open(hyFilePath.c_str(), O_RDONLY | O_CLOEXEC); if (fd == -1) { return nullptr; // Open failed. } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index adff4d644c08..9556333dbf86 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1158,7 +1158,7 @@ static int getprocname(pid_t pid, char *buf, size_t len) { FILE *f; snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid); - f = fopen(filename, "r"); + f = fopen(filename, "re"); if (!f) { *buf = '\0'; return 1; diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp index 6f975b23e5bd..578788c0f8d2 100644 --- a/core/jni/android_util_FileObserver.cpp +++ b/core/jni/android_util_FileObserver.cpp @@ -40,7 +40,7 @@ static jmethodID method_onEvent; static jint android_os_fileobserver_init(JNIEnv* env, jobject object) { #if defined(__linux__) - return (jint)inotify_init(); + return (jint)inotify_init1(IN_CLOEXEC); #else return -1; #endif diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 62aa1f38ca30..978254175da4 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -22,10 +22,10 @@ #include <utils/Log.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <cutils/sched_policy.h> #include <utils/String8.h> #include <utils/Vector.h> #include <processgroup/processgroup.h> +#include <processgroup/sched_policy.h> #include "core_jni_helpers.h" diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 5eefc8196d30..dc536b2d2dee 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -125,7 +125,7 @@ isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime, return true; } - int fd = TEMP_FAILURE_RETRY(open(filePath, O_RDONLY)); + int fd = TEMP_FAILURE_RETRY(open(filePath, O_RDONLY | O_CLOEXEC)); if (fd < 0) { ALOGV("Couldn't open file %s: %s", filePath, strerror(errno)); return true; @@ -565,7 +565,7 @@ com_android_internal_content_NativeLibraryHelper_openApkFd(JNIEnv *env, jclass, return 0; } - int dupedFd = dup(fd); + int dupedFd = fcntl(fd, F_DUPFD_CLOEXEC, 0); if (dupedFd == -1) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Failed to dup FileDescriptor: %s", strerror(errno)); diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 24bafca9c386..8259ffcd419d 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -95,7 +95,7 @@ static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int s static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid, const char* path) { - FILE* fp = fopen(path, "r"); + FILE* fp = fopen(path, "re"); if (fp == NULL) { return -1; } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index e0e73f87648f..1448d7b97eb1 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -69,13 +69,13 @@ #include <android-base/unique_fd.h> #include <cutils/fs.h> #include <cutils/multiuser.h> -#include <cutils/sched_policy.h> #include <private/android_filesystem_config.h> #include <utils/String8.h> #include <selinux/android.h> #include <seccomp_policy.h> #include <stats_event_list.h> #include <processgroup/processgroup.h> +#include <processgroup/sched_policy.h> #include "core_jni_helpers.h" #include <nativehelper/JNIHelp.h> @@ -659,7 +659,7 @@ static bool NeedsNoRandomizeWorkaround() { // Utility to close down the Zygote socket file descriptors while // the child is still running as root with Zygote's privileges. Each -// descriptor (if any) is closed via dup2(), replacing it with a valid +// descriptor (if any) is closed via dup3(), replacing it with a valid // (open) descriptor to /dev/null. static void DetachDescriptors(JNIEnv* env, @@ -667,15 +667,15 @@ static void DetachDescriptors(JNIEnv* env, fail_fn_t fail_fn) { if (fds_to_close.size() > 0) { - android::base::unique_fd devnull_fd(open("/dev/null", O_RDWR)); + android::base::unique_fd devnull_fd(open("/dev/null", O_RDWR | O_CLOEXEC)); if (devnull_fd == -1) { fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno))); } for (int fd : fds_to_close) { ALOGV("Switching descriptor %d to /dev/null", fd); - if (dup2(devnull_fd, fd) == -1) { - fail_fn(StringPrintf("Failed dup2() on descriptor %d: %s", fd, strerror(errno))); + if (dup3(devnull_fd, fd, O_CLOEXEC) == -1) { + fail_fn(StringPrintf("Failed dup3() on descriptor %d: %s", fd, strerror(errno))); } } } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 2aaf2f0a2bbe..8e6db0b74dec 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -418,13 +418,13 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { } void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const { - const int dev_null_fd = open("/dev/null", O_RDWR); + const int dev_null_fd = open("/dev/null", O_RDWR | O_CLOEXEC); if (dev_null_fd < 0) { fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno))); } - if (dup2(dev_null_fd, fd) == -1) { - fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s", + if (dup3(dev_null_fd, fd, O_CLOEXEC) == -1) { + fail_fn(android::base::StringPrintf("Failed dup3 on socket descriptor %d: %s", fd, strerror(errno))); } diff --git a/core/proto/Android.bp b/core/proto/Android.bp index 80cc2d4cab94..3b891d6b4947 100644 --- a/core/proto/Android.bp +++ b/core/proto/Android.bp @@ -21,7 +21,10 @@ cc_library_static { type: "lite", }, srcs: [ + "android/bluetooth/a2dp/enums.proto", "android/bluetooth/enums.proto", "android/bluetooth/hci/enums.proto", + "android/bluetooth/hfp/enums.proto", + "android/bluetooth/smp/enums.proto", ], } diff --git a/core/proto/android/bluetooth/a2dp/enums.proto b/core/proto/android/bluetooth/a2dp/enums.proto new file mode 100644 index 000000000000..5a025bdd6c10 --- /dev/null +++ b/core/proto/android/bluetooth/a2dp/enums.proto @@ -0,0 +1,35 @@ +/* + * Copyright 2018 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. + */ + +syntax = "proto2"; +package android.bluetooth.a2dp; + +option java_outer_classname = "BluetoothA2dpProtoEnums"; +option java_multiple_files = true; + +// A2dp playback state enum, defined from: +// frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java +enum PlaybackStateEnum { + PLAYBACK_STATE_UNKNOWN = 0; + PLAYBACK_STATE_PLAYING = 10; + PLAYBACK_STATE_NOT_PLAYING = 11; +} + +enum AudioCodingModeEnum { + AUDIO_CODING_MODE_UNKNOWN = 0; + AUDIO_CODING_MODE_HARDWARE = 1; + AUDIO_CODING_MODE_SOFTWARE = 2; +} diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto index 76c240ecff4d..a88a06cf091c 100644 --- a/core/proto/android/bluetooth/enums.proto +++ b/core/proto/android/bluetooth/enums.proto @@ -56,3 +56,57 @@ enum LinkTypeEnum { LINK_TYPE_ACL = 0x01; LINK_TYPE_ESCO = 0x02; } + +enum DeviceInfoSrcEnum { + DEVICE_INFO_SRC_UNKNOWN = 0; + // Within Android Bluetooth stack + DEVICE_INFO_INTERNAL = 1; + // Outside Android Bluetooth stack + DEVICE_INFO_EXTERNAL = 2; +} + +enum DeviceTypeEnum { + DEVICE_TYPE_UNKNOWN = 0; + DEVICE_TYPE_CLASSIC = 1; + DEVICE_TYPE_LE = 2; + DEVICE_TYPE_DUAL = 3; +} + +// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java +enum TransportTypeEnum { + TRANSPORT_TYPE_AUTO = 0; + TRANSPORT_TYPE_BREDR = 1; + TRANSPORT_TYPE_LE = 2; +} + +// Bond state enum +// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java +enum BondStateEnum { + BOND_STATE_UNKNOWN = 0; + BOND_STATE_NONE = 10; + BOND_STATE_BONDING = 11; + BOND_STATE_BONDED = 12; +} + +// Sub states within the bonding general state +enum BondSubStateEnum { + BOND_SUB_STATE_UNKNOWN = 0; + BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED = 1; + BOND_SUB_STATE_LOCAL_PIN_REQUESTED = 2; + BOND_SUB_STATE_LOCAL_PIN_REPLIED = 3; + BOND_SUB_STATE_LOCAL_SSP_REQUESTED = 4; + BOND_SUB_STATE_LOCAL_SSP_REPLIED = 5; +} + +enum UnbondReasonEnum { + UNBOND_REASON_UNKNOWN = 0; + UNBOND_REASON_AUTH_FAILED = 1; + UNBOND_REASON_AUTH_REJECTED = 2; + UNBOND_REASON_AUTH_CANCELED = 3; + UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; + UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; + UNBOND_REASON_AUTH_TIMEOUT = 6; + UNBOND_REASON_REPEATED_ATTEMPTS = 7; + UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; + UNBOND_REASON_REMOVED = 9; +} diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto index e1d96bbce68a..ef894e548351 100644 --- a/core/proto/android/bluetooth/hci/enums.proto +++ b/core/proto/android/bluetooth/hci/enums.proto @@ -351,7 +351,7 @@ enum EventEnum { EVT_COMMAND_COMPLETE = 0x0E; EVT_COMMAND_STATUS = 0x0F; EVT_HARDWARE_ERROR = 0x10; - EVT_FLUSH_OCCURED = 0x11; + EVT_FLUSH_OCCURRED = 0x11; EVT_ROLE_CHANGE = 0x12; EVT_NUM_COMPL_DATA_PKTS = 0x13; EVT_MODE_CHANGE = 0x14; @@ -517,3 +517,43 @@ enum StatusEnum { STATUS_CLB_DATA_TOO_BIG = 0x43; STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt } + +enum BqrIdEnum { + BQR_ID_UNKNOWN = 0x00; + BQR_ID_MONITOR_MODE = 0x01; + BQR_ID_APPROACH_LSTO = 0x02; + BQR_ID_A2DP_AUDIO_CHOPPY = 0x03; + BQR_ID_SCO_VOICE_CHOPPY = 0x04; +} + +enum BqrPacketTypeEnum { + BQR_PACKET_TYPE_UNKNOWN = 0x00; + BQR_PACKET_TYPE_ID = 0x01; + BQR_PACKET_TYPE_NULL = 0x02; + BQR_PACKET_TYPE_POLL = 0x03; + BQR_PACKET_TYPE_FHS = 0x04; + BQR_PACKET_TYPE_HV1 = 0x05; + BQR_PACKET_TYPE_HV2 = 0x06; + BQR_PACKET_TYPE_HV3 = 0x07; + BQR_PACKET_TYPE_DV = 0x08; + BQR_PACKET_TYPE_EV3 = 0x09; + BQR_PACKET_TYPE_EV4 = 0x0A; + BQR_PACKET_TYPE_EV5 = 0x0B; + BQR_PACKET_TYPE_2EV3 = 0x0C; + BQR_PACKET_TYPE_2EV5 = 0x0D; + BQR_PACKET_TYPE_3EV3 = 0x0E; + BQR_PACKET_TYPE_3EV5 = 0x0F; + BQR_PACKET_TYPE_DM1 = 0x10; + BQR_PACKET_TYPE_DH1 = 0x11; + BQR_PACKET_TYPE_DM3 = 0x12; + BQR_PACKET_TYPE_DH3 = 0x13; + BQR_PACKET_TYPE_DM5 = 0x14; + BQR_PACKET_TYPE_DH5 = 0x15; + BQR_PACKET_TYPE_AUX1 = 0x16; + BQR_PACKET_TYPE_2DH1 = 0x17; + BQR_PACKET_TYPE_2DH3 = 0x18; + BQR_PACKET_TYPE_2DH5 = 0x19; + BQR_PACKET_TYPE_3DH1 = 0x1A; + BQR_PACKET_TYPE_3DH3 = 0x1B; + BQR_PACKET_TYPE_3DH5 = 0x1C; +} diff --git a/core/proto/android/bluetooth/smp/enums.proto b/core/proto/android/bluetooth/smp/enums.proto new file mode 100644 index 000000000000..c6747b78dc29 --- /dev/null +++ b/core/proto/android/bluetooth/smp/enums.proto @@ -0,0 +1,58 @@ +/* + * Copyright 2019 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. + */ + +syntax = "proto2"; +package android.bluetooth.smp; + +option java_outer_classname = "BluetoothSmpProtoEnums"; +option java_multiple_files = true; + +// SMP Pairing command codes +enum CommandEnum { + CMD_UNKNOWN = 0x00; + CMD_PAIRING_REQUEST = 0x01; + CMD_PAIRING_RESPONSE = 0x02; + CMD_PAIRING_CONFIRM = 0x03; + CMD_PAIRING_RANDOM = 0x04; + CMD_PAIRING_FAILED = 0x05; + CMD_ENCRYPTION_INFON = 0x06; + CMD_MASTER_IDENTIFICATION = 0x07; + CMD_IDENTITY_INFO = 0x08; + CMD_IDENTITY_ADDR_INFO = 0x09; + CMD_SIGNING_INFO = 0x0A; + CMD_SECURITY_REQUEST = 0x0B; + CMD_PAIRING_PUBLIC_KEY = 0x0C; + CMD_PAIRING_DHKEY_CHECK = 0x0D; + CMD_PAIRING_KEYPRESS_INFO = 0x0E; +} + +enum PairingFailReasonEnum { + PAIRING_FAIL_REASON_RESERVED = 0x00; + PAIRING_FAIL_REASON_PASSKEY_ENTRY = 0x01; + PAIRING_FAIL_REASON_OOB = 0x02; + PAIRING_FAIL_REASON_AUTH_REQ = 0x03; + PAIRING_FAIL_REASON_CONFIRM_VALUE = 0x04; + PAIRING_FAIL_REASON_PAIR_NOT_SUPPORT = 0x05; + PAIRING_FAIL_REASON_ENC_KEY_SIZE = 0x06; + PAIRING_FAIL_REASON_INVALID_CMD = 0x07; + PAIRING_FAIL_REASON_UNSPECIFIED = 0x08; + PAIRING_FAIL_REASON_REPEATED_ATTEMPTS = 0x09; + PAIRING_FAIL_REASON_INVALID_PARAMETERS = 0x0A; + PAIRING_FAIL_REASON_DHKEY_CHK = 0x0B; + PAIRING_FAIL_REASON_NUMERIC_COMPARISON = 0x0C; + PAIRING_FAIL_REASON_CLASSIC_PAIRING_IN_PROGR = 0x0D; + PAIRING_FAIL_REASON_XTRANS_DERIVE_NOT_ALLOW = 0x0E; +}
\ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 344b74c6e9ab..bc5ec4938256 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1554,7 +1554,7 @@ <permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" android:protectionLevel="signature|privileged" /> - <!-- Allows a system application to access hardware packet offload capabilities. + <!-- @SystemApi Allows a system application to access hardware packet offload capabilities. @hide --> <permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" android:protectionLevel="signature|privileged" /> @@ -3231,6 +3231,12 @@ android:protectionLevel="signature|privileged" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> + <!-- Allows an application to access and modify always-on VPN configuration. + <p>Not for use by third-party or privileged applications. + @hide --> + <permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" + android:protectionLevel="signature" /> + <!-- Allows an application to capture audio output. <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index 041fb7eeb6b3..3a9d9a3ff64e 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -51,7 +51,6 @@ LOCAL_JAVA_LIBRARIES := \ org.apache.http.legacy \ android.test.base \ android.test.mock \ - framework-oahl-backward-compatibility \ framework-atb-backward-compatibility \ LOCAL_PACKAGE_NAME := FrameworksCoreTests diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index ddab25271071..212c7235f27b 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -512,6 +512,7 @@ public class SettingsBackupTest { Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS, Settings.Secure.ALWAYS_ON_VPN_APP, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, + Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, Settings.Secure.ANDROID_ID, Settings.Secure.ANR_SHOW_BACKGROUND, Settings.Secure.ASSISTANT, diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 7e20f2dde7f7..08b22c7d518a 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -17,7 +17,6 @@ package com.android.captiveportallogin; import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC; -import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME; import android.app.Activity; import android.app.AlertDialog; @@ -40,7 +39,6 @@ import android.net.http.SslError; import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Bundle; -import android.provider.Settings; import android.support.v4.widget.SwipeRefreshLayout; import android.text.TextUtils; import android.util.ArrayMap; @@ -61,16 +59,14 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.lang.InterruptedException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Objects; import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; @@ -81,6 +77,7 @@ public class CaptivePortalLoginActivity extends Activity { private static final boolean VDBG = false; private static final int SOCKET_TIMEOUT_MS = 10000; + public static final String HTTP_LOCATION_HEADER_NAME = "Location"; private enum Result { DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED), @@ -108,11 +105,11 @@ public class CaptivePortalLoginActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY); mCm = ConnectivityManager.from(this); mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); - mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); mUserAgent = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT); mUrl = getUrl(); @@ -638,7 +635,7 @@ public class CaptivePortalLoginActivity extends Activity { } private void logMetricsEvent(int event) { - MetricsLogger.action(this, event, getPackageName()); + mCaptivePortal.logEvent(event, getPackageName()); } private static final SparseArray<String> SSL_ERRORS = new SparseArray<>(); diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp index a2da0a079550..b0522f2a99a0 100644 --- a/packages/NetworkStack/Android.bp +++ b/packages/NetworkStack/Android.bp @@ -18,20 +18,23 @@ // system server on devices that run the stack there java_library { name: "NetworkStackLib", + sdk_version: "system_current", installable: true, srcs: [ "src/**/*.java", + ":framework-networkstack-shared-srcs", ":services-networkstack-shared-srcs", ], static_libs: [ - "services-netlink-lib", + "netd_aidl_interface-java", + "networkstack-aidl-interfaces-java", ] } // Updatable network stack packaged as an application android_app { name: "NetworkStack", - platform_apis: true, + sdk_version: "system_current", certificate: "platform", privileged: true, static_libs: [ diff --git a/packages/NetworkStack/TEST_MAPPING b/packages/NetworkStack/TEST_MAPPING new file mode 100644 index 000000000000..55ba5916b7d8 --- /dev/null +++ b/packages/NetworkStack/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "postsubmit": [ + { + "name": "NetworkStackTests" + } + ] +}
\ No newline at end of file diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java index 50c4dfc8d700..4fa7d6462092 100644 --- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java +++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java @@ -26,11 +26,6 @@ import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_RAW; -import static com.android.internal.util.BitUtils.bytesToBEInt; -import static com.android.internal.util.BitUtils.getUint16; -import static com.android.internal.util.BitUtils.getUint32; -import static com.android.internal.util.BitUtils.getUint8; -import static com.android.internal.util.BitUtils.uint32; import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; @@ -43,7 +38,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.NetworkUtils; import android.net.apf.ApfGenerator.IllegalInstructionException; import android.net.apf.ApfGenerator.Register; import android.net.ip.IpClient.IpClientCallbacksWrapper; @@ -52,6 +46,8 @@ import android.net.metrics.ApfStats; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; import android.net.util.InterfaceParams; +import android.net.util.NetworkStackUtils; +import android.net.util.SocketUtils; import android.os.PowerManager; import android.os.SystemClock; import android.system.ErrnoException; @@ -65,8 +61,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoBridge; - import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet4Address; @@ -205,10 +199,8 @@ public class ApfFilter { public void halt() { mStopped = true; - try { - // Interrupts the read() call the thread is blocked in. - IoBridge.closeAndSignalBlockedThreads(mSocket); - } catch (IOException ignored) {} + // Interrupts the read() call the thread is blocked in. + NetworkStackUtils.closeSocketQuietly(mSocket); } @Override @@ -475,8 +467,8 @@ public class ApfFilter { socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); SocketAddress addr = makePacketSocketAddress( (short) ETH_P_IPV6, mInterfaceParams.index); - Os.bind(socket, addr); - NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); + SocketUtils.bindSocket(socket, addr); + SocketUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); } catch(SocketException|ErrnoException e) { Log.e(TAG, "Error starting filter", e); return; @@ -1586,6 +1578,29 @@ public class ApfFilter { // TODO: move to android.net.NetworkUtils @VisibleForTesting public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { - return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength); + return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength); + } + + private static int uint8(byte b) { + return b & 0xff; + } + + private static int getUint16(ByteBuffer buffer, int position) { + return buffer.getShort(position) & 0xffff; + } + + private static long getUint32(ByteBuffer buffer, int position) { + return Integer.toUnsignedLong(buffer.getInt(position)); + } + + private static int getUint8(ByteBuffer buffer, int position) { + return uint8(buffer.get(position)); + } + + private static int bytesToBEInt(byte[] bytes) { + return (uint8(bytes[0]) << 24) + + (uint8(bytes[1]) << 16) + + (uint8(bytes[2]) << 8) + + (uint8(bytes[3])); } } diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java index 04ac9a301813..b0e8da9a7fb7 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java @@ -28,6 +28,7 @@ import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK; import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO; import static android.net.dhcp.DhcpPacket.INADDR_ANY; import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; +import static android.net.util.NetworkStackUtils.closeSocketQuietly; import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_PACKET; @@ -40,9 +41,10 @@ import static android.system.OsConstants.SO_BROADCAST; import static android.system.OsConstants.SO_RCVBUF; import static android.system.OsConstants.SO_REUSEADDR; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; + import android.content.Context; import android.net.DhcpResults; -import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.ip.IpClient; import android.net.metrics.DhcpClientEvent; @@ -64,8 +66,6 @@ import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; -import libcore.io.IoBridge; - import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet4Address; @@ -106,6 +106,12 @@ public class DhcpClient extends StateMachine { private static final boolean MSG_DBG = false; private static final boolean PACKET_DBG = false; + // Metrics events: must be kept in sync with server-side aggregation code. + /** Represents transitions from DhcpInitState to DhcpBoundState */ + private static final String EVENT_INITIAL_BOUND = "InitialBoundState"; + /** Represents transitions from and to DhcpBoundState via DhcpRenewingState */ + private static final String EVENT_RENEWING_BOUND = "RenewingBoundState"; + // Timers and timeouts. private static final int SECONDS = 1000; private static final int FIRST_TIMEOUT_MS = 2 * SECONDS; @@ -311,8 +317,8 @@ public class DhcpClient extends StateMachine { try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP); SocketAddress addr = makePacketSocketAddress((short) ETH_P_IP, mIface.index); - Os.bind(mPacketSock, addr); - NetworkUtils.attachDhcpFilter(mPacketSock); + SocketUtils.bindSocket(mPacketSock, addr); + SocketUtils.attachDhcpFilter(mPacketSock); } catch(SocketException|ErrnoException e) { Log.e(TAG, "Error creating packet socket", e); return false; @@ -328,7 +334,7 @@ public class DhcpClient extends StateMachine { Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1); Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1); Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0); - Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT); + Os.bind(mUdpSock, IPV4_ADDR_ANY, DhcpPacket.DHCP_CLIENT); } catch(SocketException|ErrnoException e) { Log.e(TAG, "Error creating UDP socket", e); return false; @@ -348,15 +354,9 @@ public class DhcpClient extends StateMachine { } } - private static void closeQuietly(FileDescriptor fd) { - try { - IoBridge.closeAndSignalBlockedThreads(fd); - } catch (IOException ignored) {} - } - private void closeSockets() { - closeQuietly(mUdpSock); - closeQuietly(mPacketSock); + closeSocketQuietly(mUdpSock); + closeSocketQuietly(mPacketSock); } class ReceiveThread extends Thread { @@ -412,7 +412,8 @@ public class DhcpClient extends StateMachine { try { if (encap == DhcpPacket.ENCAP_L2) { if (DBG) Log.d(TAG, "Broadcasting " + description); - Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr); + SocketUtils.sendTo( + mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr); } else if (encap == DhcpPacket.ENCAP_BOOTP && to.equals(INADDR_BROADCAST)) { if (DBG) Log.d(TAG, "Broadcasting " + description); // We only send L3-encapped broadcasts in DhcpRebindingState, @@ -926,9 +927,9 @@ public class DhcpClient extends StateMachine { private void logTimeToBoundState() { long now = SystemClock.elapsedRealtime(); if (mLastBoundExitTime > mLastInitEnterTime) { - logState(DhcpClientEvent.RENEWING_BOUND, (int)(now - mLastBoundExitTime)); + logState(EVENT_RENEWING_BOUND, (int) (now - mLastBoundExitTime)); } else { - logState(DhcpClientEvent.INITIAL_BOUND, (int)(now - mLastInitEnterTime)); + logState(EVENT_INITIAL_BOUND, (int) (now - mLastInitEnterTime)); } } } @@ -1019,7 +1020,7 @@ public class DhcpClient extends StateMachine { // We need to broadcast and possibly reconnect the socket to a // completely different server. - closeQuietly(mUdpSock); + closeSocketQuietly(mUdpSock); if (!initUdpSocket()) { Log.e(TAG, "Failed to recreate UDP socket"); transitionTo(mDhcpInitState); diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java index 0d298de4f5f8..0a15cd7d3bd9 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java @@ -16,12 +16,13 @@ package android.net.dhcp; -import static android.net.NetworkUtils.inet4AddressToIntHTH; -import static android.net.NetworkUtils.intToInet4AddressHTH; -import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER; import static android.net.dhcp.DhcpLease.inet4AddrToString; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; +import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS; import static java.lang.Math.min; @@ -201,7 +202,7 @@ class DhcpLeaseRepository { private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix, @Nullable Inet4Address addr) { - return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr); + return addr != null && !addr.equals(IPV4_ADDR_ANY) && !prefix.contains(addr); } @Nullable diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java index ce8b7e78d0f8..d7ff98b1f501 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java @@ -1,10 +1,13 @@ package android.net.dhcp; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; + import android.annotation.Nullable; import android.net.DhcpResults; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.metrics.DhcpErrorEvent; +import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.os.SystemProperties; import android.system.OsConstants; @@ -43,8 +46,8 @@ public abstract class DhcpPacket { public static final int MINIMUM_LEASE = 60; public static final int INFINITE_LEASE = (int) 0xffffffff; - public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY; - public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL; + public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY; + public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL; public static final byte[] ETHER_BROADCAST = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, @@ -1212,9 +1215,9 @@ public abstract class DhcpPacket { */ public DhcpResults toDhcpResults() { Inet4Address ipAddress = mYourIp; - if (ipAddress.equals(Inet4Address.ANY)) { + if (ipAddress.equals(IPV4_ADDR_ANY)) { ipAddress = mClientIp; - if (ipAddress.equals(Inet4Address.ANY)) { + if (ipAddress.equals(IPV4_ADDR_ANY)) { return null; } } @@ -1222,13 +1225,13 @@ public abstract class DhcpPacket { int prefixLength; if (mSubnetMask != null) { try { - prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask); + prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask); } catch (IllegalArgumentException e) { // Non-contiguous netmask. return null; } } else { - prefixLength = NetworkUtils.getImplicitNetmask(ipAddress); + prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress); } DhcpResults results = new DhcpResults(); diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java index dce8b619494e..96d1a287ef09 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java @@ -18,7 +18,7 @@ package android.net.dhcp; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.util.FdEventsReader; +import android.net.shared.FdEventsReader; import android.os.Handler; import android.system.Os; @@ -64,7 +64,7 @@ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payl @Override protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer) throws Exception { - final InetSocketAddress addr = new InetSocketAddress(); + final InetSocketAddress addr = new InetSocketAddress(0); final int read = Os.recvfrom( fd, packetBuffer.mBytes, 0, packetBuffer.mBytes.length, 0 /* flags */, addr); diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java index 7b112dfc125c..cd993e93998b 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java @@ -16,8 +16,6 @@ package android.net.dhcp; -import static android.net.NetworkUtils.getBroadcastAddress; -import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER; import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME; @@ -25,14 +23,19 @@ import static android.net.dhcp.DhcpPacket.DHCP_SERVER; import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; +import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOL_SOCKET; import static android.system.OsConstants.SO_BROADCAST; import static android.system.OsConstants.SO_REUSEADDR; import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission; import static java.lang.Integer.toUnsignedLong; @@ -41,7 +44,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.INetworkStackStatusCallback; import android.net.MacAddress; -import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.SharedLog; import android.net.util.SocketUtils; @@ -205,7 +207,7 @@ public class DhcpServer extends IDhcpServer.Stub { @Override public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr, @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException { - NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd); + SocketUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd); } @Override @@ -434,7 +436,7 @@ public class DhcpServer extends IDhcpServer.Stub { if (!isEmpty(request.mRelayIp)) { return request.mRelayIp; } else if (broadcastFlag) { - return (Inet4Address) Inet4Address.ALL; + return IPV4_ADDR_ALL; } else if (!isEmpty(request.mClientIp)) { return request.mClientIp; } else { @@ -517,7 +519,7 @@ public class DhcpServer extends IDhcpServer.Stub { request.mRelayIp, request.mClientMac, true /* broadcast */, message); final Inet4Address dst = isEmpty(request.mRelayIp) - ? (Inet4Address) Inet4Address.ALL + ? IPV4_ADDR_ALL : request.mRelayIp; return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst); } @@ -598,7 +600,7 @@ public class DhcpServer extends IDhcpServer.Stub { } private static boolean isEmpty(@Nullable Inet4Address address) { - return address == null || Inet4Address.ANY.equals(address); + return address == null || IPV4_ADDR_ANY.equals(address); } private class PacketListener extends DhcpPacketListener { @@ -628,11 +630,11 @@ public class DhcpServer extends IDhcpServer.Stub { // TODO: have and use an API to set a socket tag without going through the thread tag final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER); try { - mSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + mSocket = Os.socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); SocketUtils.bindSocketToInterface(mSocket, mIfName); Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1); Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1); - Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER); + Os.bind(mSocket, IPV4_ADDR_ANY, DHCP_SERVER); return mSocket; } catch (IOException | ErrnoException e) { diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java index 868f3bed4eed..3cd2aa40dfb2 100644 --- a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java +++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java @@ -16,8 +16,8 @@ package android.net.dhcp; -import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; -import static android.net.NetworkUtils.intToInet4AddressHTH; +import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE; import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU; @@ -29,7 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.NetworkUtils; +import android.net.shared.Inet4AddressUtils; import android.util.ArraySet; import java.net.Inet4Address; @@ -164,7 +164,8 @@ public class DhcpServingParams { */ @NonNull public Inet4Address getBroadcastAddress() { - return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength()); + return Inet4AddressUtils.getBroadcastAddress( + getServerInet4Addr(), serverAddr.getPrefixLength()); } /** @@ -208,7 +209,7 @@ public class DhcpServingParams { * but it must always be set explicitly before building the {@link DhcpServingParams}. */ public Builder setDefaultRouters(@NonNull Inet4Address... defaultRouters) { - return setDefaultRouters(new ArraySet<>(Arrays.asList(defaultRouters))); + return setDefaultRouters(makeArraySet(defaultRouters)); } /** @@ -238,7 +239,7 @@ public class DhcpServingParams { * building the {@link DhcpServingParams}. */ public Builder setDnsServers(@NonNull Inet4Address... dnsServers) { - return setDnsServers(new ArraySet<>(Arrays.asList(dnsServers))); + return setDnsServers(makeArraySet(dnsServers)); } /** @@ -268,7 +269,7 @@ public class DhcpServingParams { * and do not need to be set here. */ public Builder setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) { - return setExcludedAddrs(new ArraySet<>(Arrays.asList(excludedAddrs))); + return setExcludedAddrs(makeArraySet(excludedAddrs)); } /** @@ -367,4 +368,10 @@ public class DhcpServingParams { static IpPrefix makeIpPrefix(@NonNull LinkAddress addr) { return new IpPrefix(addr.getAddress(), addr.getPrefixLength()); } + + private static <T> ArraySet<T> makeArraySet(T[] elements) { + final ArraySet<T> set = new ArraySet<>(elements.length); + set.addAll(Arrays.asList(elements)); + return set; + } } diff --git a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java index 385dd52e4576..649257ae3b5f 100644 --- a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java +++ b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java @@ -20,12 +20,13 @@ import static android.net.util.SocketUtils.makePacketSocketAddress; import static android.system.OsConstants.AF_PACKET; import static android.system.OsConstants.ARPHRD_ETHER; import static android.system.OsConstants.ETH_P_ALL; +import static android.system.OsConstants.SOCK_NONBLOCK; import static android.system.OsConstants.SOCK_RAW; -import android.net.NetworkUtils; import android.net.util.ConnectivityPacketSummary; import android.net.util.InterfaceParams; import android.net.util.PacketReader; +import android.net.util.SocketUtils; import android.os.Handler; import android.system.ErrnoException; import android.system.Os; @@ -33,7 +34,7 @@ import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; -import libcore.util.HexEncoding; +import com.android.internal.util.HexDump; import java.io.FileDescriptor; import java.io.IOException; @@ -101,9 +102,10 @@ public class ConnectivityPacketTracker { protected FileDescriptor createFd() { FileDescriptor s = null; try { - s = Os.socket(AF_PACKET, SOCK_RAW, 0); - NetworkUtils.attachControlPacketFilter(s, ARPHRD_ETHER); - Os.bind(s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index)); + s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); + SocketUtils.attachControlPacketFilter(s, ARPHRD_ETHER); + SocketUtils.bindSocket( + s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index)); } catch (ErrnoException | IOException e) { logError("Failed to create packet tracking socket: ", e); closeFd(s); @@ -119,8 +121,7 @@ public class ConnectivityPacketTracker { if (summary == null) return; if (DBG) Log.d(mTag, summary); - addLogEntry(summary + - "\n[" + new String(HexEncoding.encode(recvbuf, 0, length)) + "]"); + addLogEntry(summary + "\n[" + HexDump.toHexString(recvbuf, 0, length) + "]"); } @Override diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java index ad7f85d0a30a..12fe8c507db4 100644 --- a/packages/NetworkStack/src/android/net/ip/IpClient.java +++ b/packages/NetworkStack/src/android/net/ip/IpClient.java @@ -16,6 +16,7 @@ package android.net.ip; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable; import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable; import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; @@ -29,7 +30,6 @@ import android.net.INetd; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.Network; import android.net.ProvisioningConfigurationParcelable; import android.net.ProxyInfo; import android.net.ProxyInfoParcelable; @@ -37,26 +37,21 @@ import android.net.RouteInfo; import android.net.apf.ApfCapabilities; import android.net.apf.ApfFilter; import android.net.dhcp.DhcpClient; -import android.net.ip.IIpClientCallbacks; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; import android.net.shared.InitialConfiguration; -import android.net.shared.NetdService; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; import android.net.util.SharedLog; import android.os.ConditionVariable; -import android.os.INetworkManagementService; import android.os.Message; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import android.util.SparseArray; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; @@ -65,7 +60,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; -import com.android.server.net.NetlinkTracker; +import com.android.server.NetworkObserverRegistry; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -339,8 +334,9 @@ public class IpClient extends StateMachine { private final Dependencies mDependencies; private final CountDownLatch mShutdownLatch; private final ConnectivityManager mCm; - private final INetworkManagementService mNwService; - private final NetlinkTracker mNetlinkTracker; + private final INetd mNetd; + private final NetworkObserverRegistry mObserverRegistry; + private final IpClientLinkObserver mLinkObserver; private final WakeupMessage mProvisioningTimeoutAlarm; private final WakeupMessage mDhcpActionTimeoutAlarm; private final SharedLog mLog; @@ -374,15 +370,6 @@ public class IpClient extends StateMachine { private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable(); public static class Dependencies { - public INetworkManagementService getNMS() { - return INetworkManagementService.Stub.asInterface( - ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); - } - - public INetd getNetd() { - return NetdService.getInstance(); - } - /** * Get interface parameters for the specified interface. */ @@ -391,26 +378,14 @@ public class IpClient extends StateMachine { } } - public IpClient(Context context, String ifName, IIpClientCallbacks callback) { - this(context, ifName, callback, new Dependencies()); - } - - /** - * An expanded constructor, useful for dependency injection. - * TODO: migrate all test users to mock IpClient directly and remove this ctor. - */ public IpClient(Context context, String ifName, IIpClientCallbacks callback, - INetworkManagementService nwService) { - this(context, ifName, callback, new Dependencies() { - @Override - public INetworkManagementService getNMS() { - return nwService; - } - }); + NetworkObserverRegistry observerRegistry) { + this(context, ifName, callback, observerRegistry, new Dependencies()); } @VisibleForTesting - IpClient(Context context, String ifName, IIpClientCallbacks callback, Dependencies deps) { + IpClient(Context context, String ifName, IIpClientCallbacks callback, + NetworkObserverRegistry observerRegistry, Dependencies deps) { super(IpClient.class.getSimpleName() + "." + ifName); Preconditions.checkNotNull(ifName); Preconditions.checkNotNull(callback); @@ -423,7 +398,7 @@ public class IpClient extends StateMachine { mDependencies = deps; mShutdownLatch = new CountDownLatch(1); mCm = mContext.getSystemService(ConnectivityManager.class); - mNwService = deps.getNMS(); + mObserverRegistry = observerRegistry; sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag)); mLog = sSmLogs.get(mInterfaceName); @@ -434,19 +409,15 @@ public class IpClient extends StateMachine { // TODO: Consider creating, constructing, and passing in some kind of // InterfaceController.Dependencies class. - mInterfaceCtrl = new InterfaceController(mInterfaceName, deps.getNetd(), mLog); + mNetd = mContext.getSystemService(INetd.class); + mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog); - mNetlinkTracker = new NetlinkTracker( + mLinkObserver = new IpClientLinkObserver( mInterfaceName, - new NetlinkTracker.Callback() { - @Override - public void update() { - sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED); - } - }) { + () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) { @Override - public void interfaceAdded(String iface) { - super.interfaceAdded(iface); + public void onInterfaceAdded(String iface) { + super.onInterfaceAdded(iface); if (mClatInterfaceName.equals(iface)) { mCallback.setNeighborDiscoveryOffload(false); } else if (!mInterfaceName.equals(iface)) { @@ -458,8 +429,8 @@ public class IpClient extends StateMachine { } @Override - public void interfaceRemoved(String iface) { - super.interfaceRemoved(iface); + public void onInterfaceRemoved(String iface) { + super.onInterfaceRemoved(iface); // TODO: Also observe mInterfaceName going down and take some // kind of appropriate action. if (mClatInterfaceName.equals(iface)) { @@ -571,19 +542,11 @@ public class IpClient extends StateMachine { } private void startStateMachineUpdaters() { - try { - mNwService.registerObserver(mNetlinkTracker); - } catch (RemoteException e) { - logError("Couldn't register NetlinkTracker: %s", e); - } + mObserverRegistry.registerObserverForNonblockingCallback(mLinkObserver); } private void stopStateMachineUpdaters() { - try { - mNwService.unregisterObserver(mNetlinkTracker); - } catch (RemoteException e) { - logError("Couldn't unregister NetlinkTracker: %s", e); - } + mObserverRegistry.unregisterObserver(mLinkObserver); } @Override @@ -806,7 +769,7 @@ public class IpClient extends StateMachine { // we should only call this if we know for sure that there are no IP addresses // assigned to the interface, etc. private void resetLinkProperties() { - mNetlinkTracker.clearLinkProperties(); + mLinkObserver.clearLinkProperties(); mConfiguration = null; mDhcpResults = null; mTcpBufferSizes = ""; @@ -985,10 +948,10 @@ public class IpClient extends StateMachine { // - IPv6 DNS servers // // N.B.: this is fundamentally race-prone and should be fixed by - // changing NetlinkTracker from a hybrid edge/level model to an + // changing IpClientLinkObserver from a hybrid edge/level model to an // edge-only model, or by giving IpClient its own netlink socket(s) // so as to track all required information directly. - LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); + LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties(); newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); for (RouteInfo route : netlinkLinkProperties.getRoutes()) { newLp.addRoute(route); @@ -1000,7 +963,9 @@ public class IpClient extends StateMachine { // mDhcpResults is never shared with any other owner so we don't have // to worry about concurrent modification. if (mDhcpResults != null) { - for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { + final List<RouteInfo> routes = + mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName); + for (RouteInfo route : routes) { newLp.addRoute(route); } addAllReachableDnsServers(newLp, mDhcpResults.dnsServers); @@ -1026,7 +991,7 @@ public class IpClient extends StateMachine { // specified in the InitialConfiguration have been observed with Netlink. if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) { for (IpPrefix prefix : config.directlyConnectedRoutes) { - newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName)); + newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName, RTN_UNICAST)); } } addAllReachableDnsServers(newLp, config.dnsServers); @@ -1127,7 +1092,7 @@ public class IpClient extends StateMachine { // If we have a StaticIpConfiguration attempt to apply it and // handle the result accordingly. if (mConfiguration.mStaticIpConfig != null) { - if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) { + if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) { handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); } else { return false; @@ -1165,8 +1130,7 @@ public class IpClient extends StateMachine { // necessary or does reading from settings at startup suffice?). final int numSolicits = 5; final int interSolicitIntervalMs = 750; - setNeighborParameters(mDependencies.getNetd(), mInterfaceName, - numSolicits, interSolicitIntervalMs); + setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs); } catch (Exception e) { mLog.e("Failed to adjust neighbor parameters", e); // Carry on using the system defaults (currently: 3, 1000); @@ -1383,10 +1347,8 @@ public class IpClient extends StateMachine { apfConfig.apfCapabilities = mConfiguration.mApfCapabilities; apfConfig.multicastFilter = mMulticastFiltering; // Get the Configuration for ApfFilter from Context - apfConfig.ieee802_3Filter = - mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); - apfConfig.ethTypeBlackList = - mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList); + apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames(mContext); + apfConfig.ethTypeBlackList = ApfCapabilities.getApfEthTypeBlackList(mContext); mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. diff --git a/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java new file mode 100644 index 000000000000..8ad99aa0399a --- /dev/null +++ b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ip; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.RouteInfo; +import android.util.Log; + +import com.android.server.NetworkObserver; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Keeps track of link configuration received from Netd. + * + * An instance of this class is constructed by passing in an interface name and a callback. The + * owner is then responsible for registering the tracker with NetworkObserverRegistry. When the + * class receives update notifications, it applies the update to its local LinkProperties, and if + * something has changed, notifies its owner of the update via the callback. + * + * The owner can then call {@code getLinkProperties()} in order to find out + * what changed. If in the meantime the LinkProperties stored here have changed, + * this class will return the current LinkProperties. Because each change + * triggers an update callback after the change is made, the owner may get more + * callbacks than strictly necessary (some of which may be no-ops), but will not + * be out of sync once all callbacks have been processed. + * + * Threading model: + * + * - The owner of this class is expected to create it, register it, and call + * getLinkProperties or clearLinkProperties on its thread. + * - Most of the methods in the class are implementing NetworkObserver and are called + * on the handler used to register the observer. + * - All accesses to mLinkProperties must be synchronized(this). All the other + * member variables are immutable once the object is constructed. + * + * @hide + */ +public class IpClientLinkObserver implements NetworkObserver { + private final String mTag; + + /** + * Callback used by {@link IpClientLinkObserver} to send update notifications. + */ + public interface Callback { + /** + * Called when some properties of the link were updated. + */ + void update(); + } + + private final String mInterfaceName; + private final Callback mCallback; + private final LinkProperties mLinkProperties; + private DnsServerRepository mDnsServerRepository; + + private static final boolean DBG = false; + + public IpClientLinkObserver(String iface, Callback callback) { + mTag = "NetlinkTracker/" + iface; + mInterfaceName = iface; + mCallback = callback; + mLinkProperties = new LinkProperties(); + mLinkProperties.setInterfaceName(mInterfaceName); + mDnsServerRepository = new DnsServerRepository(); + } + + private void maybeLog(String operation, String iface, LinkAddress address) { + if (DBG) { + Log.d(mTag, operation + ": " + address + " on " + iface + + " flags " + address.getFlags() + " scope " + address.getScope()); + } + } + + private void maybeLog(String operation, Object o) { + if (DBG) { + Log.d(mTag, operation + ": " + o.toString()); + } + } + + @Override + public void onInterfaceRemoved(String iface) { + maybeLog("interfaceRemoved", iface); + if (mInterfaceName.equals(iface)) { + // Our interface was removed. Clear our LinkProperties and tell our owner that they are + // now empty. Note that from the moment that the interface is removed, any further + // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd + // code that parses them will not be able to resolve the ifindex to an interface name. + clearLinkProperties(); + mCallback.update(); + } + } + + @Override + public void onInterfaceAddressUpdated(LinkAddress address, String iface) { + if (mInterfaceName.equals(iface)) { + maybeLog("addressUpdated", iface, address); + boolean changed; + synchronized (this) { + changed = mLinkProperties.addLinkAddress(address); + } + if (changed) { + mCallback.update(); + } + } + } + + @Override + public void onInterfaceAddressRemoved(LinkAddress address, String iface) { + if (mInterfaceName.equals(iface)) { + maybeLog("addressRemoved", iface, address); + boolean changed; + synchronized (this) { + changed = mLinkProperties.removeLinkAddress(address); + } + if (changed) { + mCallback.update(); + } + } + } + + @Override + public void onRouteUpdated(RouteInfo route) { + if (mInterfaceName.equals(route.getInterface())) { + maybeLog("routeUpdated", route); + boolean changed; + synchronized (this) { + changed = mLinkProperties.addRoute(route); + } + if (changed) { + mCallback.update(); + } + } + } + + @Override + public void onRouteRemoved(RouteInfo route) { + if (mInterfaceName.equals(route.getInterface())) { + maybeLog("routeRemoved", route); + boolean changed; + synchronized (this) { + changed = mLinkProperties.removeRoute(route); + } + if (changed) { + mCallback.update(); + } + } + } + + @Override + public void onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { + if (mInterfaceName.equals(iface)) { + maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses)); + boolean changed = mDnsServerRepository.addServers(lifetime, addresses); + if (changed) { + synchronized (this) { + mDnsServerRepository.setDnsServersOn(mLinkProperties); + } + mCallback.update(); + } + } + } + + /** + * Returns a copy of this object's LinkProperties. + */ + public synchronized LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + /** + * Reset this object's LinkProperties. + */ + public synchronized void clearLinkProperties() { + // Clear the repository before clearing mLinkProperties. That way, if a clear() happens + // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in + // mLinkProperties, as desired. + mDnsServerRepository = new DnsServerRepository(); + mLinkProperties.clear(); + mLinkProperties.setInterfaceName(mInterfaceName); + } + + /** + * Tracks DNS server updates received from Netlink. + * + * The network may announce an arbitrary number of DNS servers in Router Advertisements at any + * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be + * used any more. In this way, the network can gracefully migrate clients from one set of DNS + * servers to another. Announcements can both raise and lower the lifetime, and an announcement + * can expire servers by announcing them with a lifetime of zero. + * + * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of + * DNS servers at any given time. These are referred to as the current servers. In case all the + * current servers expire, the class also keeps track of a larger (but limited) number of + * servers that are promoted to current servers when the current ones expire. In order to + * minimize updates to the rest of the system (and potentially expensive cache flushes) this + * class attempts to keep the list of current servers constant where possible. More + * specifically, the list of current servers is only updated if a new server is learned and + * there are not yet {@code NUM_CURRENT_SERVERS} current servers, or if one or more of the + * current servers expires or is pushed out of the set. Therefore, the current servers will not + * necessarily be the ones with the highest lifetime, but the ones learned first. + * + * This is by design: if instead the class always preferred the servers with the highest + * lifetime, a (misconfigured?) network where two or more routers announce more than + * {@code NUM_CURRENT_SERVERS} unique servers would cause persistent oscillations. + * + * TODO: Currently servers are only expired when a new DNS update is received. + * Update them using timers, or possibly on every notification received by NetlinkTracker. + * + * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink + * notifications are sent by multiple threads. If future threads use alarms to expire, those + * alarms must also be synchronized(this). + * + */ + private static class DnsServerRepository { + + /** How many DNS servers we will use. 3 is suggested by RFC 6106. */ + static final int NUM_CURRENT_SERVERS = 3; + + /** How many DNS servers we'll keep track of, in total. */ + static final int NUM_SERVERS = 12; + + /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */ + private Set<InetAddress> mCurrentServers; + + public static final String TAG = "DnsServerRepository"; + + /** + * Stores all the DNS servers we know about, for use when the current servers expire. + * Always sorted in order of decreasing expiry. The elements in this list are also the + * values of mIndex, and may be elements in mCurrentServers. + */ + private ArrayList<DnsServerEntry> mAllServers; + + /** + * Indexes the servers so we can update their lifetimes more quickly in the common case + * where servers are not being added, but only being refreshed. + */ + private HashMap<InetAddress, DnsServerEntry> mIndex; + + DnsServerRepository() { + mCurrentServers = new HashSet<>(); + mAllServers = new ArrayList<>(NUM_SERVERS); + mIndex = new HashMap<>(NUM_SERVERS); + } + + /** Sets the DNS servers of the provided LinkProperties object to the current servers. */ + public synchronized void setDnsServersOn(LinkProperties lp) { + lp.setDnsServers(mCurrentServers); + } + + /** + * Notifies the class of new DNS server information. + * @param lifetime the time in seconds that the DNS servers are valid. + * @param addresses the string representations of the IP addresses of DNS servers to use. + */ + public synchronized boolean addServers(long lifetime, String[] addresses) { + // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned. + // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds + // (136 years) is close enough. + long now = System.currentTimeMillis(); + long expiry = now + 1000 * lifetime; + + // Go through the list of servers. For each one, update the entry if one exists, and + // create one if it doesn't. + for (String addressString : addresses) { + InetAddress address; + try { + address = InetAddresses.parseNumericAddress(addressString); + } catch (IllegalArgumentException ex) { + continue; + } + + if (!updateExistingEntry(address, expiry)) { + // There was no entry for this server. Create one, unless it's already expired + // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned). + if (expiry > now) { + DnsServerEntry entry = new DnsServerEntry(address, expiry); + mAllServers.add(entry); + mIndex.put(address, entry); + } + } + } + + // Sort the servers by expiry. + Collections.sort(mAllServers); + + // Prune excess entries and update the current server list. + return updateCurrentServers(); + } + + private synchronized boolean updateExistingEntry(InetAddress address, long expiry) { + DnsServerEntry existing = mIndex.get(address); + if (existing != null) { + existing.expiry = expiry; + return true; + } + return false; + } + + private synchronized boolean updateCurrentServers() { + long now = System.currentTimeMillis(); + boolean changed = false; + + // Prune excess or expired entries. + for (int i = mAllServers.size() - 1; i >= 0; i--) { + if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) { + DnsServerEntry removed = mAllServers.remove(i); + mIndex.remove(removed.address); + changed |= mCurrentServers.remove(removed.address); + } else { + break; + } + } + + // Add servers to the current set, in order of decreasing lifetime, until it has enough. + // Prefer existing servers over new servers in order to minimize updates to the rest of + // the system and avoid persistent oscillations. + for (DnsServerEntry entry : mAllServers) { + if (mCurrentServers.size() < NUM_CURRENT_SERVERS) { + changed |= mCurrentServers.add(entry.address); + } else { + break; + } + } + return changed; + } + } + + /** + * Represents a DNS server entry with an expiry time. + * + * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first. + * The ordering of entries with the same lifetime is unspecified, because given two servers with + * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much + * faster than comparing the IP address as well. + * + * Note: this class has a natural ordering that is inconsistent with equals. + */ + private static class DnsServerEntry implements Comparable<DnsServerEntry> { + /** The IP address of the DNS server. */ + public final InetAddress address; + /** The time until which the DNS server may be used. A Java millisecond time as might be + * returned by currentTimeMillis(). */ + public long expiry; + + DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException { + this.address = address; + this.expiry = expiry; + } + + public int compareTo(DnsServerEntry other) { + return Long.compare(other.expiry, this.expiry); + } + } +} diff --git a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java index eb993a4243a9..b29d61793a61 100644 --- a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java +++ b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java @@ -20,6 +20,10 @@ import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; import static android.net.netlink.NetlinkConstants.hexify; import static android.net.netlink.NetlinkConstants.stringForNlMsgType; import static android.net.util.SocketUtils.makeNetlinkSocketAddress; +import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.NETLINK_ROUTE; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; import android.net.MacAddress; import android.net.netlink.NetlinkErrorMessage; @@ -27,8 +31,10 @@ import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; +import android.net.util.NetworkStackUtils; import android.net.util.PacketReader; import android.net.util.SharedLog; +import android.net.util.SocketUtils; import android.os.Handler; import android.os.SystemClock; import android.system.ErrnoException; @@ -36,10 +42,6 @@ import android.system.Os; import android.system.OsConstants; import android.util.Log; -import com.android.internal.util.BitUtils; - -import libcore.io.IoUtils; - import java.io.FileDescriptor; import java.net.InetAddress; import java.net.SocketAddress; @@ -79,7 +81,7 @@ public class IpNeighborMonitor extends PacketReader { 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); try { - NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg); + NetlinkSocket.sendOneShotKernelMessage(NETLINK_ROUTE, msg); } catch (ErrnoException e) { Log.e(TAG, "Error " + msgSnippet + ": " + e); return -e.errno; @@ -147,8 +149,8 @@ public class IpNeighborMonitor extends PacketReader { FileDescriptor fd = null; try { - fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE); - Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)); + fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE); + SocketUtils.bindSocket(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)); NetlinkSocket.connectToKernel(fd); if (VDBG) { @@ -157,7 +159,7 @@ public class IpNeighborMonitor extends PacketReader { } } catch (ErrnoException|SocketException e) { logError("Failed to create rtnetlink socket", e); - IoUtils.closeQuietly(fd); + NetworkStackUtils.closeSocketQuietly(fd); return null; } @@ -186,7 +188,7 @@ public class IpNeighborMonitor extends PacketReader { final int srcPortId = nlMsg.getHeader().nlmsg_pid; if (srcPortId != 0) { - mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId)); + mLog.e("non-kernel source portId: " + Integer.toUnsignedLong(srcPortId)); break; } diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java index 761db6822fb4..76a03387a12d 100644 --- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java +++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java @@ -31,15 +31,15 @@ import android.net.metrics.IpReachabilityEvent; import android.net.netlink.StructNdMsg; import android.net.util.InterfaceParams; import android.net.util.SharedLog; +import android.os.ConditionVariable; import android.os.Handler; +import android.os.Looper; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DumpUtils; -import com.android.internal.util.DumpUtils.Dump; import java.io.PrintWriter; import java.net.Inet6Address; @@ -215,15 +215,20 @@ public class IpReachabilityMonitor { } public void dump(PrintWriter pw) { - DumpUtils.dumpAsync( - mIpNeighborMonitor.getHandler(), - new Dump() { - @Override - public void dump(PrintWriter pw, String prefix) { - pw.println(describeWatchList("\n")); - } - }, - pw, "", 1000); + if (Looper.myLooper() == mIpNeighborMonitor.getHandler().getLooper()) { + pw.println(describeWatchList("\n")); + return; + } + + final ConditionVariable cv = new ConditionVariable(false); + mIpNeighborMonitor.getHandler().post(() -> { + pw.println(describeWatchList("\n")); + cv.open(); + }); + + if (!cv.block(1000)) { + pw.println("Timed out waiting for IpReachabilityMonitor dump"); + } } private String describeWatchList() { return describeWatchList(" "); } diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java index cddb91f65d0f..98123a5c7261 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java @@ -14,16 +14,30 @@ * limitations under the License. */ -package android.net.dhcp; +package android.net.util; + +import java.io.FileDescriptor; +import java.io.IOException; /** - * TODO: remove this class after migrating clients. + * Collection of utilities for the network stack. */ -public class DhcpClient { - public static final int CMD_PRE_DHCP_ACTION = 1003; - public static final int CMD_POST_DHCP_ACTION = 1004; - public static final int CMD_PRE_DHCP_ACTION_COMPLETE = 1006; +public class NetworkStackUtils { + + /** + * @return True if the array is null or 0-length. + */ + public static <T> boolean isEmpty(T[] array) { + return array == null || array.length == 0; + } - public static final int DHCP_SUCCESS = 1; - public static final int DHCP_FAILURE = 2; + /** + * Close a socket, ignoring any exception while closing. + */ + public static void closeSocketQuietly(FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } } diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java index 4aec6b6753a6..94b1e9f2e14e 100644 --- a/packages/NetworkStack/src/android/net/util/PacketReader.java +++ b/packages/NetworkStack/src/android/net/util/PacketReader.java @@ -18,6 +18,7 @@ package android.net.util; import static java.lang.Math.max; +import android.net.shared.FdEventsReader; import android.os.Handler; import android.system.Os; diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserver.java b/packages/NetworkStack/src/com/android/server/NetworkObserver.java new file mode 100644 index 000000000000..cccec0bb5d40 --- /dev/null +++ b/packages/NetworkStack/src/com/android/server/NetworkObserver.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 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.server; + +import android.net.LinkAddress; +import android.net.RouteInfo; + +/** + * Observer for network events, to use with {@link NetworkObserverRegistry}. + */ +public interface NetworkObserver { + + /** + * @see android.net.INetdUnsolicitedEventListener#onInterfaceChanged(java.lang.String, boolean) + */ + default void onInterfaceChanged(String ifName, boolean up) {} + + /** + * @see android.net.INetdUnsolicitedEventListener#onInterfaceRemoved(String) + */ + default void onInterfaceRemoved(String ifName) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onInterfaceAddressUpdated(String, String, int, int) + */ + default void onInterfaceAddressUpdated(LinkAddress address, String ifName) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onInterfaceAddressRemoved(String, String, int, int) + */ + default void onInterfaceAddressRemoved(LinkAddress address, String ifName) {} + + /** + * @see android.net.INetdUnsolicitedEventListener#onInterfaceLinkStateChanged(String, boolean) + */ + default void onInterfaceLinkStateChanged(String ifName, boolean up) {} + + /** + * @see android.net.INetdUnsolicitedEventListener#onInterfaceAdded(String) + */ + default void onInterfaceAdded(String ifName) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onInterfaceClassActivityChanged(boolean, int, long, int) + */ + default void onInterfaceClassActivityChanged( + boolean isActive, int label, long timestamp, int uid) {} + + /** + * @see android.net.INetdUnsolicitedEventListener#onQuotaLimitReached(String, String) + */ + default void onQuotaLimitReached(String alertName, String ifName) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onInterfaceDnsServerInfo(String, long, String[]) + */ + default void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onRouteChanged(boolean, String, String, String) + */ + default void onRouteUpdated(RouteInfo route) {} + + /** + * @see android.net.INetdUnsolicitedEventListener + * #onRouteChanged(boolean, String, String, String) + */ + default void onRouteRemoved(RouteInfo route) {} +} diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java new file mode 100644 index 000000000000..6fb4b0d79a64 --- /dev/null +++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2019 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.server; + +import static android.net.RouteInfo.RTN_UNICAST; + +import android.annotation.NonNull; +import android.net.INetd; +import android.net.INetdUnsolicitedEventListener; +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.RouteInfo; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A class for reporting network events to clients. + * + * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to + * all INetworkManagementEventObserver objects that have registered with it. + */ +public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub { + private static final String TAG = NetworkObserverRegistry.class.getSimpleName(); + + /** + * Constructs a new NetworkObserverRegistry. + * + * <p>Only one registry should be used per process since netd will silently ignore multiple + * registrations from the same process. + */ + NetworkObserverRegistry() {} + + /** + * Start listening for Netd events. + * + * <p>This should be called before allowing any observer to be registered. + */ + void register(@NonNull INetd netd) throws RemoteException { + netd.registerUnsolicitedEventListener(this); + } + + private final ConcurrentHashMap<NetworkObserver, Optional<Handler>> mObservers = + new ConcurrentHashMap<>(); + + /** + * Registers the specified observer and start sending callbacks to it. + * This method may be called on any thread. + */ + public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) { + if (handler == null) { + throw new IllegalArgumentException("handler must be non-null"); + } + mObservers.put(observer, Optional.of(handler)); + } + + /** + * Registers the specified observer, and start sending callbacks to it. + * + * <p>This method must only be called with callbacks that are nonblocking, such as callbacks + * that only send a message to a StateMachine. + */ + public void registerObserverForNonblockingCallback(@NonNull NetworkObserver observer) { + mObservers.put(observer, Optional.empty()); + } + + /** + * Unregisters the specified observer and stop sending callbacks to it. + * This method may be called on any thread. + */ + public void unregisterObserver(@NonNull NetworkObserver observer) { + mObservers.remove(observer); + } + + @FunctionalInterface + private interface NetworkObserverEventCallback { + void sendCallback(NetworkObserver o); + } + + private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) { + // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before + // creation will be processed, those added during traversal may or may not. + for (Map.Entry<NetworkObserver, Optional<Handler>> entry : mObservers.entrySet()) { + final NetworkObserver observer = entry.getKey(); + final Optional<Handler> handler = entry.getValue(); + if (handler.isPresent()) { + handler.get().post(() -> callback.sendCallback(observer)); + return; + } + + try { + callback.sendCallback(observer); + } catch (RuntimeException e) { + Log.e(TAG, "Error sending callback to observer", e); + } + } + } + + @Override + public void onInterfaceClassActivityChanged(boolean isActive, + int label, long timestamp, int uid) { + invokeForAllObservers(o -> o.onInterfaceClassActivityChanged( + isActive, label, timestamp, uid)); + } + + /** + * Notify our observers of a limit reached. + */ + @Override + public void onQuotaLimitReached(String alertName, String ifName) { + invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName)); + } + + @Override + public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) { + invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers)); + } + + @Override + public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) { + final LinkAddress address = new LinkAddress(addr, flags, scope); + invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName)); + } + + @Override + public void onInterfaceAddressRemoved(String addr, + String ifName, int flags, int scope) { + final LinkAddress address = new LinkAddress(addr, flags, scope); + invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName)); + } + + @Override + public void onInterfaceAdded(String ifName) { + invokeForAllObservers(o -> o.onInterfaceAdded(ifName)); + } + + @Override + public void onInterfaceRemoved(String ifName) { + invokeForAllObservers(o -> o.onInterfaceRemoved(ifName)); + } + + @Override + public void onInterfaceChanged(String ifName, boolean up) { + invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up)); + } + + @Override + public void onInterfaceLinkStateChanged(String ifName, boolean up) { + invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up)); + } + + @Override + public void onRouteChanged(boolean updated, String route, String gateway, String ifName) { + final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), + ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), + ifName, RTN_UNICAST); + if (updated) { + invokeForAllObservers(o -> o.onRouteUpdated(processRoute)); + } else { + invokeForAllObservers(o -> o.onRouteRemoved(processRoute)); + } + } + + @Override + public void onStrictCleartextDetected(int uid, String hex) {} +} diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java index 4080ddf9e73f..cedcb84e9d08 100644 --- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java +++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java @@ -19,6 +19,7 @@ package com.android.server; import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; +import static android.net.shared.NetworkParcelableUtil.fromStableParcelable; import static com.android.server.util.PermissionUtil.checkDumpPermission; import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission; @@ -29,11 +30,12 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkStackConnector; import android.net.Network; -import android.net.NetworkRequest; +import android.net.NetworkParcelable; import android.net.PrivateDnsConfigParcel; import android.net.dhcp.DhcpServer; import android.net.dhcp.DhcpServingParams; @@ -65,6 +67,7 @@ import java.util.Iterator; */ public class NetworkStackService extends Service { private static final String TAG = NetworkStackService.class.getSimpleName(); + private static NetworkStackConnector sConnector; /** * Create a binder connector for the system server to communicate with the network stack. @@ -72,8 +75,11 @@ public class NetworkStackService extends Service { * <p>On platforms where the network stack runs in the system server process, this method may * be called directly instead of obtaining the connector by binding to the service. */ - public static IBinder makeConnector(Context context) { - return new NetworkStackConnector(context); + public static synchronized IBinder makeConnector(Context context) { + if (sConnector == null) { + sConnector = new NetworkStackConnector(context); + } + return sConnector; } @NonNull @@ -85,6 +91,8 @@ public class NetworkStackService extends Service { private static class NetworkStackConnector extends INetworkStackConnector.Stub { private static final int NUM_VALIDATION_LOG_LINES = 20; private final Context mContext; + private final INetd mNetd; + private final NetworkObserverRegistry mObserverRegistry; private final ConnectivityManager mCm; @GuardedBy("mIpClients") private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>(); @@ -106,7 +114,15 @@ public class NetworkStackService extends Service { NetworkStackConnector(Context context) { mContext = context; + mNetd = (INetd) context.getSystemService(Context.NETD_SERVICE); + mObserverRegistry = new NetworkObserverRegistry(); mCm = context.getSystemService(ConnectivityManager.class); + + try { + mObserverRegistry.register(mNetd); + } catch (RemoteException e) { + mLog.e("Error registering observer on Netd", e); + } } @NonNull @@ -135,19 +151,18 @@ public class NetworkStackService extends Service { } @Override - public void makeNetworkMonitor(int netId, String name, INetworkMonitorCallbacks cb) + public void makeNetworkMonitor( + NetworkParcelable network, String name, INetworkMonitorCallbacks cb) throws RemoteException { - final Network network = new Network(netId, false /* privateDnsBypass */); - final NetworkRequest defaultRequest = mCm.getDefaultRequest(); - final SharedLog log = addValidationLogs(network, name); - final NetworkMonitor nm = new NetworkMonitor( - mContext, cb, network, defaultRequest, log); + final Network parsedNetwork = fromStableParcelable(network); + final SharedLog log = addValidationLogs(parsedNetwork, name); + final NetworkMonitor nm = new NetworkMonitor(mContext, cb, parsedNetwork, log); cb.onNetworkMonitorCreated(new NetworkMonitorImpl(nm)); } @Override public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException { - final IpClient ipClient = new IpClient(mContext, ifName, cb); + final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry); synchronized (mIpClients) { final Iterator<WeakReference<IpClient>> it = mIpClients.iterator(); diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java index 6b31b82ec3cc..b34efc46f3b4 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java @@ -31,6 +31,7 @@ import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE; import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS; import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK; import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS; +import static android.net.util.NetworkStackUtils.isEmpty; import android.annotation.Nullable; import android.app.PendingIntent; @@ -46,7 +47,6 @@ import android.net.INetworkMonitorCallbacks; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.net.ProxyInfo; import android.net.TrafficStats; import android.net.Uri; @@ -80,7 +80,6 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.RingBufferIndices; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -93,6 +92,7 @@ import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -309,14 +309,14 @@ public class NetworkMonitor extends StateMachine { private long mLastProbeTime; public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network, - NetworkRequest defaultRequest, SharedLog validationLog) { - this(context, cb, network, defaultRequest, new IpConnectivityLog(), validationLog, + SharedLog validationLog) { + this(context, cb, network, new IpConnectivityLog(), validationLog, Dependencies.DEFAULT); } @VisibleForTesting protected NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network, - NetworkRequest defaultRequest, IpConnectivityLog logger, SharedLog validationLogs, + IpConnectivityLog logger, SharedLog validationLogs, Dependencies deps) { // Add suffix indicating which NetworkMonitor we're talking about. super(TAG + "/" + network.toString()); @@ -368,8 +368,7 @@ public class NetworkMonitor extends StateMachine { // we can ever fetch them. // TODO: Delete ASAP. mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkCapabilities.clearAll(); + mNetworkCapabilities = new NetworkCapabilities(null); } /** @@ -688,6 +687,15 @@ public class NetworkMonitor extends StateMachine { } sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response); } + + @Override + public void logEvent(int eventId, String packageName) + throws RemoteException { + mContext.enforceCallingPermission( + android.Manifest.permission.CONNECTIVITY_INTERNAL, + "CaptivePortal"); + mCallback.logCaptivePortalLoginEvent(eventId, packageName); + } })); final CaptivePortalProbeResult probeRes = mLastPortalProbeResult; intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl); @@ -1146,7 +1154,10 @@ public class NetworkMonitor extends StateMachine { return null; } - return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue); + final Collection<CaptivePortalProbeSpec> specs = + CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue); + final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()]; + return specs.toArray(specsArray); } catch (Exception e) { // Don't let a misconfiguration bootloop the system. Log.e(TAG, "Error parsing configured fallback probe specs", e); @@ -1169,7 +1180,7 @@ public class NetworkMonitor extends StateMachine { } private CaptivePortalProbeSpec nextFallbackSpec() { - if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) { + if (isEmpty(mCaptivePortalFallbackSpecs)) { return null; } // Randomly change spec without memory. Also randomize the first attempt. diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java index eedaf30c055f..804765e33a87 100644 --- a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java +++ b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java @@ -16,6 +16,10 @@ package com.android.server.util; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; + +import java.net.Inet4Address; + /** * Network constants used by the network stack. */ @@ -79,6 +83,8 @@ public final class NetworkStackConstants { public static final int IPV4_SRC_ADDR_OFFSET = 12; public static final int IPV4_DST_ADDR_OFFSET = 16; public static final int IPV4_ADDR_LEN = 4; + public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff); + public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0); /** * IPv6 constants. diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java index 51d50d9eb13a..4abd77e9cfde 100644 --- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java @@ -21,6 +21,8 @@ import static android.net.dhcp.DhcpLease.HOSTNAME_NONE; import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC; import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC; +import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -55,7 +57,6 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class DhcpLeaseRepositoryTest { - private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY; private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247"); private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241"); private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243"); @@ -108,7 +109,7 @@ public class DhcpLeaseRepositoryTest { MacAddress newMac = MacAddress.fromBytes(hwAddrBytes); final String hostname = "host_" + i; final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname); assertNotNull(lease); assertEquals(newMac, lease.getHwAddr()); @@ -130,7 +131,7 @@ public class DhcpLeaseRepositoryTest { try { mRepo.getOffer(null, TEST_MAC_2, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); fail("Should be out of addresses"); } catch (DhcpLeaseRepository.OutOfAddressesException e) { // Expected @@ -181,11 +182,11 @@ public class DhcpLeaseRepositoryTest { public void testGetOffer_StableAddress() throws Exception { for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) { final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); // Same lease is offered twice final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertEquals(lease, newLease); } } @@ -196,7 +197,7 @@ public class DhcpLeaseRepositoryTest { mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS); DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertTrue(newPrefix.contains(lease.getNetAddr())); } @@ -205,7 +206,7 @@ public class DhcpLeaseRepositoryTest { requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1); DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertEquals(TEST_INETADDR_1, offer.getNetAddr()); assertEquals(TEST_HOSTNAME_1, offer.getHostname()); } @@ -213,12 +214,13 @@ public class DhcpLeaseRepositoryTest { @Test public void testGetOffer_ClientIdHasExistingLease() throws Exception { final byte[] clientId = new byte[] { 1, 2 }; - mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY /* clientAddr */, - INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1); + mRepo.requestLease(clientId, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */, + IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, + TEST_HOSTNAME_1); // Different MAC, but same clientId DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertEquals(TEST_INETADDR_1, offer.getNetAddr()); assertEquals(TEST_HOSTNAME_1, offer.getHostname()); } @@ -227,12 +229,13 @@ public class DhcpLeaseRepositoryTest { public void testGetOffer_DifferentClientId() throws Exception { final byte[] clientId1 = new byte[] { 1, 2 }; final byte[] clientId2 = new byte[] { 3, 4 }; - mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY /* clientAddr */, - INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1); + mRepo.requestLease(clientId1, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */, + IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, + TEST_HOSTNAME_1); // Same MAC, different client ID DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); // Obtains a different address assertNotEquals(TEST_INETADDR_1, offer.getNetAddr()); assertEquals(HOSTNAME_NONE, offer.getHostname()); @@ -241,7 +244,7 @@ public class DhcpLeaseRepositoryTest { @Test public void testGetOffer_RequestedAddress() throws Exception { - DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */, + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1); assertEquals(TEST_INETADDR_1, offer.getNetAddr()); assertEquals(TEST_HOSTNAME_1, offer.getHostname()); @@ -250,14 +253,14 @@ public class DhcpLeaseRepositoryTest { @Test public void testGetOffer_RequestedAddressInUse() throws Exception { requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1); - DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY /* relayAddr */, + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE); assertNotEquals(TEST_INETADDR_1, offer.getNetAddr()); } @Test public void testGetOffer_RequestedAddressReserved() throws Exception { - DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */, + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */, TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE); assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr()); } @@ -265,7 +268,7 @@ public class DhcpLeaseRepositoryTest { @Test public void testGetOffer_RequestedAddressInvalid() throws Exception { final Inet4Address invalidAddr = parseAddr4("192.168.42.0"); - DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */, + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */, invalidAddr /* reqAddr */, HOSTNAME_NONE); assertNotEquals(invalidAddr, offer.getNetAddr()); } @@ -273,7 +276,7 @@ public class DhcpLeaseRepositoryTest { @Test public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception { final Inet4Address invalidAddr = parseAddr4("192.168.254.2"); - DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */, + DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */, invalidAddr /* reqAddr */, HOSTNAME_NONE); assertNotEquals(invalidAddr, offer.getNetAddr()); } @@ -322,7 +325,7 @@ public class DhcpLeaseRepositoryTest { @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class) public void testRequestLease_SelectingRelayInInvalidSubnet() throws Exception { - mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* clientAddr */, + mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */, parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, true /* sidSet */, HOSTNAME_NONE); } @@ -419,14 +422,14 @@ public class DhcpLeaseRepositoryTest { public void testReleaseLease_StableOffer() throws Exception { for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) { final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); requestLeaseSelecting(mac, lease.getNetAddr()); mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr()); // Same lease is offered after it was released final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertEquals(lease.getNetAddr(), newLease.getNetAddr()); } } @@ -434,13 +437,13 @@ public class DhcpLeaseRepositoryTest { @Test public void testMarkLeaseDeclined() throws Exception { final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); mRepo.markLeaseDeclined(lease.getNetAddr()); // Same lease is not offered again final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); assertNotEquals(lease.getNetAddr(), newLease.getNetAddr()); } @@ -457,16 +460,16 @@ public class DhcpLeaseRepositoryTest { // Last 2 addresses: addresses marked declined should be used final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1); requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr()); final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, - INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2); + IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2); requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr()); // Now out of addresses try { - mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY /* relayAddr */, + mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE); fail("Repository should be out of addresses and throw"); } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ } @@ -480,7 +483,8 @@ public class DhcpLeaseRepositoryTest { private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr, @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet) throws DhcpLeaseRepository.DhcpLeaseException { - return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, INET4_ANY /* relayAddr */, + return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, + IPV4_ADDR_ANY /* relayAddr */, reqAddr, sidSet, hostname); } @@ -490,7 +494,7 @@ public class DhcpLeaseRepositoryTest { private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr, @NonNull Inet4Address reqAddr, @Nullable String hostname) throws DhcpLeaseRepository.DhcpLeaseException { - return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, hostname, + return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, hostname, true /* sidSet */); } @@ -507,7 +511,7 @@ public class DhcpLeaseRepositoryTest { */ private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr, @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException { - return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE, + return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE, false /* sidSet */); } diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java index a592809618e6..7544e72da02e 100644 --- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java @@ -16,9 +16,27 @@ package android.net.dhcp; -import static android.net.NetworkUtils.getBroadcastAddress; -import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; -import static android.net.dhcp.DhcpPacket.*; +import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS; +import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER; +import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME; +import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME; +import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_ACK; +import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_OFFER; +import static android.net.dhcp.DhcpPacket.DHCP_MTU; +import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME; +import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME; +import static android.net.dhcp.DhcpPacket.DHCP_ROUTER; +import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK; +import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO; +import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; +import static android.net.dhcp.DhcpPacket.ENCAP_L2; +import static android.net.dhcp.DhcpPacket.ENCAP_L3; +import static android.net.dhcp.DhcpPacket.INADDR_ANY; +import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; +import static android.net.dhcp.DhcpPacket.ParseException; +import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; +import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -30,11 +48,15 @@ import android.net.DhcpResults; import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.metrics.DhcpErrorEvent; -import android.support.test.runner.AndroidJUnit4; import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import com.android.internal.util.HexDump; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.ByteArrayOutputStream; import java.net.Inet4Address; import java.nio.ByteBuffer; @@ -44,10 +66,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Random; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - @RunWith(AndroidJUnit4.class) @SmallTest public class DhcpPacketTest { @@ -60,9 +78,9 @@ public class DhcpPacketTest { SERVER_ADDR, PREFIX_LENGTH); private static final String HOSTNAME = "testhostname"; private static final short MTU = 1500; - // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code + // Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code // doesn't use == instead of equals when comparing addresses. - private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0"); + private static final Inet4Address ANY = v4Address("0.0.0.0"); private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java index 3ca0564f24d6..1004382b3adf 100644 --- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java +++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java @@ -17,8 +17,8 @@ package android.net.dhcp; import static android.net.InetAddresses.parseNumericAddress; -import static android.net.NetworkUtils.inet4AddressToIntHTH; import static android.net.dhcp.DhcpServingParams.MTU_UNSET; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -27,8 +27,8 @@ import static junit.framework.Assert.assertTrue; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.dhcp.DhcpServingParams.InvalidParameterException; +import android.net.shared.Inet4AddressUtils; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -200,7 +200,7 @@ public class DhcpServingParamsTest { } private static int[] toIntArray(Collection<Inet4Address> addrs) { - return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray(); + return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray(); } private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) { diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java index f21809fdbc1c..7e57d1eb00b0 100644 --- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java +++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java @@ -46,7 +46,6 @@ import android.net.RouteInfo; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; -import android.os.INetworkManagementService; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -54,7 +53,8 @@ import android.test.mock.MockContentResolver; import com.android.internal.R; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.server.net.BaseNetworkObserver; +import com.android.server.NetworkObserver; +import com.android.server.NetworkObserverRegistry; import org.junit.Before; import org.junit.Test; @@ -87,15 +87,15 @@ public class IpClientTest { @Mock private Context mContext; @Mock private ConnectivityManager mCm; - @Mock private INetworkManagementService mNMService; + @Mock private NetworkObserverRegistry mObserverRegistry; @Mock private INetd mNetd; @Mock private Resources mResources; @Mock private IIpClientCallbacks mCb; @Mock private AlarmManager mAlarm; - @Mock private IpClient.Dependencies mDependecies; + @Mock private IpClient.Dependencies mDependencies; private MockContentResolver mContentResolver; - private BaseNetworkObserver mObserver; + private NetworkObserver mObserver; private InterfaceParams mIfParams; @Before @@ -103,9 +103,8 @@ public class IpClientTest { MockitoAnnotations.initMocks(this); when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm); - when(mContext.getSystemServiceName(ConnectivityManager.class)) - .thenReturn(Context.CONNECTIVITY_SERVICE); - when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm); + when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm); + when(mContext.getSystemService(INetd.class)).thenReturn(mNetd); when(mContext.getResources()).thenReturn(mResources); when(mResources.getInteger(R.integer.config_networkAvoidBadWifi)) .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE); @@ -115,28 +114,24 @@ public class IpClientTest { when(mContext.getContentResolver()).thenReturn(mContentResolver); mIfParams = null; - - when(mDependecies.getNMS()).thenReturn(mNMService); - when(mDependecies.getNetd()).thenReturn(mNetd); } private void setTestInterfaceParams(String ifname) { mIfParams = (ifname != null) ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC) : null; - when(mDependecies.getInterfaceParams(anyString())).thenReturn(mIfParams); + when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams); } private IpClient makeIpClient(String ifname) throws Exception { setTestInterfaceParams(ifname); - final IpClient ipc = new IpClient(mContext, ifname, mCb, mDependecies); + final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false); verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname); - ArgumentCaptor<BaseNetworkObserver> arg = - ArgumentCaptor.forClass(BaseNetworkObserver.class); - verify(mNMService, times(1)).registerObserver(arg.capture()); + ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class); + verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture()); mObserver = arg.getValue(); - reset(mNMService); + reset(mObserverRegistry); reset(mNetd); // Verify IpClient doesn't call onLinkPropertiesChange() when it starts. verify(mCb, never()).onLinkPropertiesChange(any()); @@ -154,7 +149,8 @@ public class IpClientTest { public void testNullInterfaceNameMostDefinitelyThrows() throws Exception { setTestInterfaceParams(null); try { - final IpClient ipc = new IpClient(mContext, null, mCb, mDependecies); + final IpClient ipc = new IpClient( + mContext, null, mCb, mObserverRegistry, mDependencies); ipc.shutdown(); fail(); } catch (NullPointerException npe) { @@ -167,7 +163,8 @@ public class IpClientTest { final String ifname = "lo"; setTestInterfaceParams(ifname); try { - final IpClient ipc = new IpClient(mContext, ifname, null, mDependecies); + final IpClient ipc = new IpClient( + mContext, ifname, null, mObserverRegistry, mDependencies); ipc.shutdown(); fail(); } catch (NullPointerException npe) { @@ -178,14 +175,16 @@ public class IpClientTest { @Test public void testInvalidInterfaceDoesNotThrow() throws Exception { setTestInterfaceParams(TEST_IFNAME); - final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies); + final IpClient ipc = new IpClient( + mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies); ipc.shutdown(); } @Test public void testInterfaceNotFoundFailsImmediately() throws Exception { setTestInterfaceParams(null); - final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies); + final IpClient ipc = new IpClient( + mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies); ipc.startProvisioning(new ProvisioningConfiguration()); verify(mCb, times(1)).onProvisioningFailure(any()); ipc.shutdown(); @@ -249,13 +248,13 @@ public class IpClientTest { // Add N - 1 addresses for (int i = 0; i < lastAddr; i++) { - mObserver.addressUpdated(iface, new LinkAddress(addresses[i])); + mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface); verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any()); reset(mCb); } // Add Nth address - mObserver.addressUpdated(iface, new LinkAddress(addresses[lastAddr])); + mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface); LinkProperties want = linkproperties(links(addresses), routes(prefixes)); want.setInterfaceName(iface); verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat( diff --git a/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java b/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java index dced7435ee74..6e11c409e104 100644 --- a/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java +++ b/packages/NetworkStack/tests/src/android/net/util/PacketReaderTest.java @@ -17,7 +17,13 @@ package android.net.util; import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE; -import static android.system.OsConstants.*; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_SNDTIMEO; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -31,10 +37,12 @@ import android.system.ErrnoException; import android.system.Os; import android.system.StructTimeval; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.UncheckedIOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet6Address; @@ -45,13 +53,6 @@ import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import org.junit.runner.RunWith; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import libcore.io.IoBridge; - /** * Tests for PacketReader. * @@ -80,7 +81,7 @@ public class PacketReaderTest { protected FileDescriptor createFd() { FileDescriptor s = null; try { - s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + s = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); Os.bind(s, LOOPBACK6, 0); mLocalSockName = (InetSocketAddress) Os.getsockname(s); Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO); diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java index d31fa7732e66..d11bb64213c3 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java @@ -21,7 +21,6 @@ import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -51,7 +50,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; -import android.net.NetworkRequest; import android.net.captiveportal.CaptivePortalProbeResult; import android.net.metrics.IpConnectivityLog; import android.net.util.SharedLog; @@ -103,7 +101,6 @@ public class NetworkMonitorTest { private @Mock NetworkMonitor.Dependencies mDependencies; private @Mock INetworkMonitorCallbacks mCallbacks; private @Spy Network mNetwork = new Network(TEST_NETID); - private NetworkRequest mRequest; private static final int TEST_NETID = 4242; @@ -178,10 +175,6 @@ public class NetworkMonitorTest { InetAddresses.parseNumericAddress("192.168.0.0") }).when(mNetwork).getAllByName(any()); - mRequest = new NetworkRequest.Builder() - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_RESTRICTED) - .build(); // Default values. Individual tests can override these. when(mCm.getLinkProperties(any())).thenReturn(TEST_LINKPROPERTIES); when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES); @@ -195,9 +188,9 @@ public class NetworkMonitorTest { private class WrappedNetworkMonitor extends NetworkMonitor { private long mProbeTime = 0; - WrappedNetworkMonitor(Context context, Network network, NetworkRequest defaultRequest, - IpConnectivityLog logger, Dependencies deps) { - super(context, mCallbacks, network, defaultRequest, logger, + WrappedNetworkMonitor(Context context, Network network, IpConnectivityLog logger, + Dependencies deps) { + super(context, mCallbacks, network, logger, new SharedLog("test_nm"), deps); } @@ -213,7 +206,7 @@ public class NetworkMonitorTest { private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() { final WrappedNetworkMonitor nm = new WrappedNetworkMonitor( - mContext, mNetwork, mRequest, mLogger, mDependencies); + mContext, mNetwork, mLogger, mDependencies); when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES); nm.start(); waitForIdle(nm.getHandler()); @@ -222,7 +215,7 @@ public class NetworkMonitorTest { private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() { final WrappedNetworkMonitor nm = new WrappedNetworkMonitor( - mContext, mNetwork, mRequest, mLogger, mDependencies); + mContext, mNetwork, mLogger, mDependencies); when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES); nm.start(); waitForIdle(nm.getHandler()); @@ -231,7 +224,7 @@ public class NetworkMonitorTest { private NetworkMonitor makeMonitor() { final NetworkMonitor nm = new NetworkMonitor( - mContext, mCallbacks, mNetwork, mRequest, mLogger, mValidationLogger, + mContext, mCallbacks, mNetwork, mLogger, mValidationLogger, mDependencies); nm.start(); waitForIdle(nm.getHandler()); diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS index d188c65be883..d87908738b56 100644 --- a/packages/SettingsLib/OWNERS +++ b/packages/SettingsLib/OWNERS @@ -4,7 +4,7 @@ asargent@google.com dehboxturtle@google.com dhnishi@google.com dling@google.com -dsandler@google.com +dsandler@android.com evanlaird@google.com jackqdyulei@google.com jmonk@google.com diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 2a3cf3ebeedf..3f6ebf0fe09d 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -1,6 +1,6 @@ set noparent -dsandler@google.com +dsandler@android.com adamcohen@google.com asc@google.com diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index 8172e717850b..1d0b9b6d83db 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -20,6 +20,7 @@ package="com.android.vpndialogs"> <uses-permission android:name="android.permission.CONTROL_VPN" /> + <uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" /> <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <application android:label="VpnDialogs" diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bc9f9e3f5a41..08e49034aa6c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -40,6 +40,7 @@ import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME; import static android.net.shared.NetworkMonitorUtils.isValidationRequired; +import static android.net.shared.NetworkParcelableUtil.toStableParcelable; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -98,10 +99,10 @@ import android.net.VpnService; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; -import android.net.shared.NetdService; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; +import android.net.util.NetdService; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -144,6 +145,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; +import com.android.internal.logging.MetricsLogger; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; @@ -1884,6 +1886,12 @@ public class ConnectivityService extends IConnectivityManager.Stub "ConnectivityService"); } + private void enforceControlAlwaysOnVpnPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CONTROL_ALWAYS_ON_VPN, + "ConnectivityService"); + } + private void enforceNetworkStackSettingsOrSetup() { enforceAnyPermissionOf( android.Manifest.permission.NETWORK_SETTINGS, @@ -1891,6 +1899,12 @@ public class ConnectivityService extends IConnectivityManager.Stub android.Manifest.permission.NETWORK_STACK); } + private void enforceNetworkStackPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_STACK, + "ConnectivityService"); + } + private boolean checkNetworkStackPermission() { return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( android.Manifest.permission.NETWORK_STACK); @@ -2671,6 +2685,11 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNai.network.netId)); } + + @Override + public void logCaptivePortalLoginEvent(int eventId, String packageName) { + new MetricsLogger().action(eventId, packageName); + } } private boolean networkRequiresValidation(NetworkAgentInfo nai) { @@ -4161,8 +4180,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) { - enforceConnectivityInternalPermission(); + public boolean setAlwaysOnVpnPackage( + int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) { + enforceControlAlwaysOnVpnPermission(); enforceCrossUserPermission(userId); synchronized (mVpns) { @@ -4176,11 +4196,11 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return false; } - if (!vpn.setAlwaysOnPackage(packageName, lockdown)) { + if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) { return false; } if (!startAlwaysOnVpn(userId)) { - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); return false; } } @@ -4189,7 +4209,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getAlwaysOnVpnPackage(int userId) { - enforceConnectivityInternalPermission(); + enforceControlAlwaysOnVpnPermission(); enforceCrossUserPermission(userId); synchronized (mVpns) { @@ -4203,6 +4223,36 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override + public boolean isVpnLockdownEnabled(int userId) { + enforceControlAlwaysOnVpnPermission(); + enforceCrossUserPermission(userId); + + synchronized (mVpns) { + Vpn vpn = mVpns.get(userId); + if (vpn == null) { + Slog.w(TAG, "User " + userId + " has no Vpn configuration"); + return false; + } + return vpn.getLockdown(); + } + } + + @Override + public List<String> getVpnLockdownWhitelist(int userId) { + enforceControlAlwaysOnVpnPermission(); + enforceCrossUserPermission(userId); + + synchronized (mVpns) { + Vpn vpn = mVpns.get(userId); + if (vpn == null) { + Slog.w(TAG, "User " + userId + " has no Vpn configuration"); + return null; + } + return vpn.getLockdownWhitelist(); + } + } + + @Override public int checkMobileProvisioning(int suggestedTimeOutMs) { // TODO: Remove? Any reason to trigger a provisioning check? return -1; @@ -4431,7 +4481,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) { Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user " + userId); - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); } } } @@ -4983,8 +5033,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("registerNetworkAgent " + nai); final long token = Binder.clearCallingIdentity(); try { - mContext.getSystemService(NetworkStack.class) - .makeNetworkMonitor(nai.network, name, new NetworkMonitorCallbacks(nai)); + mContext.getSystemService(NetworkStack.class).makeNetworkMonitor( + toStableParcelable(nai.network), name, new NetworkMonitorCallbacks(nai)); } finally { Binder.restoreCallingIdentity(token); } @@ -6311,7 +6361,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mVpns) { final String alwaysOnPackage = getAlwaysOnVpnPackage(userId); if (alwaysOnPackage != null) { - setAlwaysOnVpnPackage(userId, null, false); + setAlwaysOnVpnPackage(userId, null, false, null); setVpnPackageAuthorization(alwaysOnPackage, userId, false); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 371276fbd2ae..126bf6556538 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -44,7 +44,7 @@ import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; -import android.net.shared.NetdService; +import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 2f66fd7dc7c7..da4df22d7b02 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -47,8 +47,10 @@ import android.app.ActivityManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.INetd; +import android.net.INetdUnsolicitedEventListener; import android.net.INetworkManagementEventObserver; import android.net.ITetheringStatsProvider; +import android.net.InetAddresses; import android.net.InterfaceConfiguration; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; @@ -60,8 +62,7 @@ import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.TetherStatsParcel; import android.net.UidRange; -import android.net.shared.NetdService; -import android.net.shared.NetworkObserverRegistry; +import android.net.util.NetdService; import android.os.BatteryStats; import android.os.Binder; import android.os.Handler; @@ -205,13 +206,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub private INetd mNetdService; - private NMSNetworkObserverRegistry mNetworkObserverRegistry; + private final NetdUnsolicitedEventListener mNetdUnsolicitedEventListener; private IBatteryStats mBatteryStats; private final Thread mThread; private CountDownLatch mConnectedSignal = new CountDownLatch(1); + private final RemoteCallbackList<INetworkManagementEventObserver> mObservers = + new RemoteCallbackList<>(); + private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory(); @GuardedBy("mTetheringStatsProviders") @@ -321,6 +325,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub mDaemonHandler = new Handler(FgThread.get().getLooper()); + mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener(); + // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); @@ -339,7 +345,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mFgHandler = null; mThread = null; mServices = null; - mNetworkObserverRegistry = null; + mNetdUnsolicitedEventListener = null; } static NetworkManagementService create(Context context, String socket, SystemServices services) @@ -387,12 +393,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub @Override public void registerObserver(INetworkManagementEventObserver observer) { - mNetworkObserverRegistry.registerObserver(observer); + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + mObservers.register(observer); } @Override public void unregisterObserver(INetworkManagementEventObserver observer) { - mNetworkObserverRegistry.unregisterObserver(observer); + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + mObservers.unregister(observer); } @FunctionalInterface @@ -400,97 +408,123 @@ public class NetworkManagementService extends INetworkManagementService.Stub public void sendCallback(INetworkManagementEventObserver o) throws RemoteException; } - private class NMSNetworkObserverRegistry extends NetworkObserverRegistry { - NMSNetworkObserverRegistry(Context context, Handler handler, INetd netd) - throws RemoteException { - super(context, handler, netd); - } - - /** - * Notify our observers of a change in the data activity state of the interface - */ - @Override - public void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos, - int uid, boolean fromRadio) { - final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type); - int powerState = isActive - ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH - : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; - - if (isMobile) { - if (!fromRadio) { - if (mMobileActivityFromRadio) { - // If this call is not coming from a report from the radio itself, but we - // have previously received reports from the radio, then we will take the - // power state to just be whatever the radio last reported. - powerState = mLastPowerStateFromRadio; - } - } else { - mMobileActivityFromRadio = true; - } - if (mLastPowerStateFromRadio != powerState) { - mLastPowerStateFromRadio = powerState; - try { - getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid); - } catch (RemoteException e) { - } + private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) { + final int length = mObservers.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + try { + eventCallback.sendCallback(mObservers.getBroadcastItem(i)); + } catch (RemoteException | RuntimeException e) { } } + } finally { + mObservers.finishBroadcast(); + } + } - if (ConnectivityManager.isNetworkTypeWifi(type)) { - if (mLastPowerStateFromWifi != powerState) { - mLastPowerStateFromWifi = powerState; - try { - getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid); - } catch (RemoteException e) { - } - } - } + /** + * Notify our observers of an interface status change + */ + private void notifyInterfaceStatusChanged(String iface, boolean up) { + invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up)); + } - if (!isMobile || fromRadio || !mMobileActivityFromRadio) { - // Report the change in data activity. We don't do this if this is a change - // on the mobile network, that is not coming from the radio itself, and we - // have previously seen change reports from the radio. In that case only - // the radio is the authority for the current state. - final boolean active = isActive; - super.notifyInterfaceClassActivity(type, isActive, tsNanos, uid, fromRadio); - } + /** + * Notify our observers of an interface link state change + * (typically, an Ethernet cable has been plugged-in or unplugged). + */ + private void notifyInterfaceLinkStateChanged(String iface, boolean up) { + invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up)); + } + + /** + * Notify our observers of an interface addition. + */ + private void notifyInterfaceAdded(String iface) { + invokeForAllObservers(o -> o.interfaceAdded(iface)); + } + + /** + * Notify our observers of an interface removal. + */ + private void notifyInterfaceRemoved(String iface) { + // netd already clears out quota and alerts for removed ifaces; update + // our sanity-checking state. + mActiveAlerts.remove(iface); + mActiveQuotas.remove(iface); + invokeForAllObservers(o -> o.interfaceRemoved(iface)); + } - boolean report = false; - synchronized (mIdleTimerLock) { - if (mActiveIdleTimers.isEmpty()) { - // If there are no idle timers, we are not monitoring activity, so we - // are always considered active. - isActive = true; + /** + * Notify our observers of a limit reached. + */ + private void notifyLimitReached(String limitName, String iface) { + invokeForAllObservers(o -> o.limitReached(limitName, iface)); + } + + /** + * Notify our observers of a change in the data activity state of the interface + */ + private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos, + int uid, boolean fromRadio) { + final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type); + int powerState = isActive + ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH + : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; + if (isMobile) { + if (!fromRadio) { + if (mMobileActivityFromRadio) { + // If this call is not coming from a report from the radio itself, but we + // have previously received reports from the radio, then we will take the + // power state to just be whatever the radio last reported. + powerState = mLastPowerStateFromRadio; } - if (mNetworkActive != isActive) { - mNetworkActive = isActive; - report = isActive; + } else { + mMobileActivityFromRadio = true; + } + if (mLastPowerStateFromRadio != powerState) { + mLastPowerStateFromRadio = powerState; + try { + getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid); + } catch (RemoteException e) { } } - if (report) { - reportNetworkActive(); + } + + if (ConnectivityManager.isNetworkTypeWifi(type)) { + if (mLastPowerStateFromWifi != powerState) { + mLastPowerStateFromWifi = powerState; + try { + getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid); + } catch (RemoteException e) { + } } } - /** - * Notify our observers of an interface removal. - */ - @Override - public void notifyInterfaceRemoved(String iface) { - // netd already clears out quota and alerts for removed ifaces; update - // our sanity-checking state. - mActiveAlerts.remove(iface); - mActiveQuotas.remove(iface); - super.notifyInterfaceRemoved(iface); + if (!isMobile || fromRadio || !mMobileActivityFromRadio) { + // Report the change in data activity. We don't do this if this is a change + // on the mobile network, that is not coming from the radio itself, and we + // have previously seen change reports from the radio. In that case only + // the radio is the authority for the current state. + final boolean active = isActive; + invokeForAllObservers(o -> o.interfaceClassDataActivityChanged( + Integer.toString(type), active, tsNanos)); } - @Override - public void onStrictCleartextDetected(int uid, String hex) throws RemoteException { - // Don't need to post to mDaemonHandler because the only thing - // that notifyCleartextNetwork does is post to a handler - ActivityManager.getService().notifyCleartextNetwork(uid, - HexDump.hexStringToByteArray(hex)); + boolean report = false; + synchronized (mIdleTimerLock) { + if (mActiveIdleTimers.isEmpty()) { + // If there are no idle timers, we are not monitoring activity, so we + // are always considered active. + isActive = true; + } + if (mNetworkActive != isActive) { + mNetworkActive = isActive; + report = isActive; + } + } + if (report) { + reportNetworkActive(); } } @@ -519,8 +553,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub return; } // No current code examines the interface parameter in a global alert. Just pass null. - mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyLimitReached( - LIMIT_GLOBAL_ALERT, null)); + mDaemonHandler.post(() -> notifyLimitReached(LIMIT_GLOBAL_ALERT, null)); } } @@ -552,11 +585,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub private void connectNativeNetdService() { mNetdService = mServices.getNetd(); try { - mNetworkObserverRegistry = new NMSNetworkObserverRegistry( - mContext, mDaemonHandler, mNetdService); - if (DBG) Slog.d(TAG, "Registered NetworkObserverRegistry"); + mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener); + if (DBG) Slog.d(TAG, "Register unsolicited event listener"); } catch (RemoteException | ServiceSpecificException e) { - Slog.wtf(TAG, "Failed to register NetworkObserverRegistry: " + e); + Slog.e(TAG, "Failed to set Netd unsolicited event listener " + e); } } @@ -660,6 +692,118 @@ public class NetworkManagementService extends INetworkManagementService.Stub } + /** + * Notify our observers of a new or updated interface address. + */ + private void notifyAddressUpdated(String iface, LinkAddress address) { + invokeForAllObservers(o -> o.addressUpdated(iface, address)); + } + + /** + * Notify our observers of a deleted interface address. + */ + private void notifyAddressRemoved(String iface, LinkAddress address) { + invokeForAllObservers(o -> o.addressRemoved(iface, address)); + } + + /** + * Notify our observers of DNS server information received. + */ + private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { + invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses)); + } + + /** + * Notify our observers of a route change. + */ + private void notifyRouteChange(boolean updated, RouteInfo route) { + if (updated) { + invokeForAllObservers(o -> o.routeUpdated(route)); + } else { + invokeForAllObservers(o -> o.routeRemoved(route)); + } + } + + private class NetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub { + @Override + public void onInterfaceClassActivityChanged(boolean isActive, + int label, long timestamp, int uid) throws RemoteException { + final long timestampNanos; + if (timestamp <= 0) { + timestampNanos = SystemClock.elapsedRealtimeNanos(); + } else { + timestampNanos = timestamp; + } + mDaemonHandler.post(() -> + notifyInterfaceClassActivity(label, isActive, timestampNanos, uid, false)); + } + + @Override + public void onQuotaLimitReached(String alertName, String ifName) + throws RemoteException { + mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName)); + } + + @Override + public void onInterfaceDnsServerInfo(String ifName, + long lifetime, String[] servers) throws RemoteException { + mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers)); + } + + @Override + public void onInterfaceAddressUpdated(String addr, + String ifName, int flags, int scope) throws RemoteException { + final LinkAddress address = new LinkAddress(addr, flags, scope); + mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address)); + } + + @Override + public void onInterfaceAddressRemoved(String addr, + String ifName, int flags, int scope) throws RemoteException { + final LinkAddress address = new LinkAddress(addr, flags, scope); + mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address)); + } + + @Override + public void onInterfaceAdded(String ifName) throws RemoteException { + mDaemonHandler.post(() -> notifyInterfaceAdded(ifName)); + } + + @Override + public void onInterfaceRemoved(String ifName) throws RemoteException { + mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName)); + } + + @Override + public void onInterfaceChanged(String ifName, boolean up) + throws RemoteException { + mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up)); + } + + @Override + public void onInterfaceLinkStateChanged(String ifName, boolean up) + throws RemoteException { + mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up)); + } + + @Override + public void onRouteChanged(boolean updated, + String route, String gateway, String ifName) throws RemoteException { + final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), + ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), + ifName); + mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute)); + } + + @Override + public void onStrictCleartextDetected(int uid, String hex) throws RemoteException { + // Don't need to post to mDaemonHandler because the only thing + // that notifyCleartextNetwork does is post to a handler + ActivityManager.getService().notifyCleartextNetwork(uid, + HexDump.hexStringToByteArray(hex)); + } + } + // // Netd Callback handling // @@ -708,18 +852,16 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw new IllegalStateException(errorMessage); } if (cooked[2].equals("added")) { - mNetworkObserverRegistry.notifyInterfaceAdded(cooked[3]); + notifyInterfaceAdded(cooked[3]); return true; } else if (cooked[2].equals("removed")) { - mNetworkObserverRegistry.notifyInterfaceRemoved(cooked[3]); + notifyInterfaceRemoved(cooked[3]); return true; } else if (cooked[2].equals("changed") && cooked.length == 5) { - mNetworkObserverRegistry.notifyInterfaceStatusChanged( - cooked[3], cooked[4].equals("up")); + notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); return true; } else if (cooked[2].equals("linkstate") && cooked.length == 5) { - mNetworkObserverRegistry.notifyInterfaceLinkStateChanged( - cooked[3], cooked[4].equals("up")); + notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); return true; } throw new IllegalStateException(errorMessage); @@ -733,7 +875,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw new IllegalStateException(errorMessage); } if (cooked[2].equals("alert")) { - mNetworkObserverRegistry.notifyLimitReached(cooked[3], cooked[4]); + notifyLimitReached(cooked[3], cooked[4]); return true; } throw new IllegalStateException(errorMessage); @@ -759,9 +901,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub timestampNanos = SystemClock.elapsedRealtimeNanos(); } boolean isActive = cooked[2].equals("active"); - mNetworkObserverRegistry.notifyInterfaceClassActivity( - Integer.parseInt(cooked[3]), isActive, - timestampNanos, processUid, false); + notifyInterfaceClassActivity(Integer.parseInt(cooked[3]), + isActive, timestampNanos, processUid, false); return true; // break; case NetdResponseCode.InterfaceAddressChange: @@ -787,9 +928,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub } if (cooked[2].equals("updated")) { - mNetworkObserverRegistry.notifyAddressUpdated(iface, address); + notifyAddressUpdated(iface, address); } else { - mNetworkObserverRegistry.notifyAddressRemoved(iface, address); + notifyAddressRemoved(iface, address); } return true; // break; @@ -809,8 +950,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw new IllegalStateException(errorMessage); } String[] servers = cooked[5].split(","); - mNetworkObserverRegistry.notifyInterfaceDnsServerInfo( - cooked[3], lifetime, servers); + notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers); } return true; // break; @@ -849,8 +989,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub InetAddress gateway = null; if (via != null) gateway = InetAddress.parseNumericAddress(via); RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev); - mNetworkObserverRegistry.notifyRouteChange( - cooked[2].equals("updated"), route); + notifyRouteChange(cooked[2].equals("updated"), route); return true; } catch (IllegalArgumentException e) {} } @@ -1313,8 +1452,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub if (ConnectivityManager.isNetworkTypeMobile(type)) { mNetworkActive = false; } - mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyInterfaceClassActivity( - type, true /* isActive */, SystemClock.elapsedRealtimeNanos(), -1, false)); + mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true, + SystemClock.elapsedRealtimeNanos(), -1, false)); } } @@ -1337,9 +1476,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub throw new IllegalStateException(e); } mActiveIdleTimers.remove(iface); - mDaemonHandler.post(() -> mNetworkObserverRegistry.notifyInterfaceClassActivity( - params.type, false /* isActive */, SystemClock.elapsedRealtimeNanos(), -1, - false)); + mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type, false, + SystemClock.elapsedRealtimeNanos(), -1, false)); } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 1798f388ab27..43af36f86f3d 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -52,6 +52,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsReasonInfo; import android.util.LocalLog; import android.util.StatsLog; @@ -206,9 +207,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList; - private CallQuality mCallQuality; + private CallQuality mCallQuality = new CallQuality(); - private CallAttributes mCallAttributes; + private CallAttributes mCallAttributes = new CallAttributes(new PreciseCallState(), + TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()); private int[] mSrvccState; @@ -226,6 +228,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int mCallDisconnectCause = DisconnectCause.NOT_VALID; + private List<ImsReasonInfo> mImsReasonInfo = null; + private int mCallPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID; private boolean mCarrierNetworkChangeState = false; @@ -376,6 +380,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellLocation = new Bundle[numPhones]; mCellInfo = new ArrayList<List<CellInfo>>(); mSrvccState = new int[numPhones]; + mImsReasonInfo = new ArrayList<ImsReasonInfo>(); mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>(); mEmergencyNumberList = new HashMap<>(); for (int i = 0; i < numPhones; i++) { @@ -393,6 +398,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallForwarding[i] = false; mCellLocation[i] = new Bundle(); mCellInfo.add(i, null); + mImsReasonInfo.add(i, null); mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE; mPhysicalChannelConfigs.add(i, new ArrayList<PhysicalChannelConfig>()); } @@ -738,6 +744,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) { + try { + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + } catch (RemoteException ex) { + remove(r.binder); + } + } if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) { try { r.callback.onPreciseDataConnectionStateChanged( @@ -1590,6 +1603,34 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + public void notifyImsDisconnectCause(int subId, ImsReasonInfo imsReasonInfo) { + if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) { + return; + } + int phoneId = SubscriptionManager.getPhoneId(subId); + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mImsReasonInfo.set(phoneId, imsReasonInfo); + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) + && idMatch(r.subId, subId, phoneId)) { + try { + if (DBG_LOC) { + log("notifyImsCallDisconnectCause: mImsReasonInfo=" + + imsReasonInfo + " r=" + r); + } + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + public void notifyPreciseDataConnectionFailed(String apnType, String apn, @DataFailCause.FailCause int failCause) { if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) { @@ -1626,7 +1667,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { int phoneId = SubscriptionManager.getPhoneId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mSrvccState[phoneId] = state; + mSrvccState[phoneId] = state; for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) && @@ -1837,6 +1878,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mDataConnectionState=" + mDataConnectionState[i]); pw.println("mCellLocation=" + mCellLocation[i]); pw.println("mCellInfo=" + mCellInfo.get(i)); + pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i).toString()); pw.decreaseIndent(); } pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState); @@ -2126,6 +2168,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); } + if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); + } + return true; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 62a1b036daa0..9141ccb387bd 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -151,7 +151,7 @@ public class Vpn { .divide(BigInteger.valueOf(100)); } // How many routes to evaluate before bailing and declaring this Vpn should provide - // the INTERNET capability. This is necessary because computing the adress space is + // the INTERNET capability. This is necessary because computing the address space is // O(n²) and this is running in the system service, so a limit is needed to alleviate // the risk of attack. // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm @@ -165,6 +165,7 @@ public class Vpn { private final NetworkInfo mNetworkInfo; private String mPackage; private int mOwnerUID; + private boolean mIsPackageTargetingAtLeastQ; private String mInterface; private Connection mConnection; private LegacyVpnRunner mLegacyVpnRunner; @@ -194,6 +195,12 @@ public class Vpn { private boolean mLockdown = false; /** + * Set of packages in addition to the VPN app itself that can access the network directly when + * VPN is not connected even if {@code mLockdown} is set. + */ + private @NonNull List<String> mLockdownWhitelist = Collections.emptyList(); + + /** * List of UIDs for which networking should be blocked until VPN is ready, during brief periods * when VPN is not running. For example, during system startup or after a crash. * @see mLockdown @@ -220,6 +227,7 @@ public class Vpn { mPackage = VpnConfig.LEGACY_VPN; mOwnerUID = getAppUid(mPackage, mUserHandle); + mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage); try { netService.registerObserver(mObserver); @@ -261,8 +269,11 @@ public class Vpn { public void updateCapabilities() { final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; + // Only apps targeting Q and above can explicitly declare themselves as metered. + final boolean isAlwaysMetered = + mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered); updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, - mNetworkCapabilities); + mNetworkCapabilities, isAlwaysMetered); if (mNetworkAgent != null) { mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); @@ -271,11 +282,13 @@ public class Vpn { @VisibleForTesting public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, - NetworkCapabilities caps) { + NetworkCapabilities caps, boolean isAlwaysMetered) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; - boolean metered = false; + // VPN's meteredness is OR'd with isAlwaysMetered and meteredness of its underlying + // networks. + boolean metered = isAlwaysMetered; boolean roaming = false; boolean congested = false; @@ -320,9 +333,9 @@ public class Vpn { * * Used to enable/disable legacy VPN lockdown. * - * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)}; - * previous settings from calling that function will be replaced and saved with the - * always-on state. + * This uses the same ip rule mechanism as + * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling + * that function will be replaced and saved with the always-on state. * * @param lockdown whether to prevent all traffic outside of a VPN. */ @@ -419,12 +432,14 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. + * @param lockdownWhitelist packages to be whitelisted from lockdown. * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ - public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) { + public synchronized boolean setAlwaysOnPackage( + String packageName, boolean lockdown, List<String> lockdownWhitelist) { enforceControlPermissionOrInternalCaller(); - if (setAlwaysOnPackageInternal(packageName, lockdown)) { + if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) { saveAlwaysOnPackage(); return true; } @@ -439,15 +454,27 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. + * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if + * {@code lockdown} is {@code true}. Packages must not contain commas. * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ @GuardedBy("this") - private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) { + private boolean setAlwaysOnPackageInternal( + String packageName, boolean lockdown, List<String> lockdownWhitelist) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; } + if (lockdownWhitelist != null) { + for (String pkg : lockdownWhitelist) { + if (pkg.contains(",")) { + Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg); + return false; + } + } + } + if (packageName != null) { // Pre-authorize new always-on VPN package. if (!setPackageAuthorization(packageName, true)) { @@ -460,13 +487,18 @@ public class Vpn { } mLockdown = (mAlwaysOn && lockdown); + mLockdownWhitelist = (mLockdown && lockdownWhitelist != null) + ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist)) + : Collections.emptyList(); + if (isCurrentPreparedPackage(packageName)) { updateAlwaysOnNotification(mNetworkInfo.getDetailedState()); + setVpnForcedLocked(mLockdown); } else { // Prepare this app. The notification will update as a side-effect of updateState(). + // It also calls setVpnForcedLocked(). prepareInternal(packageName); } - setVpnForcedLocked(mLockdown); return true; } @@ -478,7 +510,6 @@ public class Vpn { * @return the package name of the VPN controller responsible for always-on VPN, * or {@code null} if none is set or always-on VPN is controlled through * lockdown instead. - * @hide */ public synchronized String getAlwaysOnPackage() { enforceControlPermissionOrInternalCaller(); @@ -486,6 +517,13 @@ public class Vpn { } /** + * @return an immutable list of packages whitelisted from always-on VPN lockdown. + */ + public synchronized List<String> getLockdownWhitelist() { + return mLockdown ? mLockdownWhitelist : null; + } + + /** * Save the always-on package and lockdown config into Settings.Secure */ @GuardedBy("this") @@ -496,6 +534,9 @@ public class Vpn { getAlwaysOnPackage(), mUserHandle); mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle); + mSystemServices.settingsSecurePutStringForUser( + Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, + String.join(",", mLockdownWhitelist), mUserHandle); } finally { Binder.restoreCallingIdentity(token); } @@ -512,7 +553,11 @@ public class Vpn { Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle); final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0; - setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown); + final String whitelistString = mSystemServices.settingsSecureGetStringForUser( + Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle); + final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString) + ? Collections.emptyList() : Arrays.asList(whitelistString.split(",")); + setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages); } finally { Binder.restoreCallingIdentity(token); } @@ -532,7 +577,7 @@ public class Vpn { } // Remove always-on VPN if it's not supported. if (!isAlwaysOnPackageSupported(alwaysOnPackage)) { - setAlwaysOnPackage(null, false); + setAlwaysOnPackage(null, false, null); return false; } // Skip if the service is already established. This isn't bulletproof: it's not bound @@ -686,6 +731,7 @@ public class Vpn { Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); mPackage = newPackage; mOwnerUID = getAppUid(newPackage, mUserHandle); + mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage); try { mNetd.allowProtect(mOwnerUID); } catch (Exception e) { @@ -751,6 +797,21 @@ public class Vpn { return result; } + private boolean doesPackageTargetAtLeastQ(String packageName) { + if (VpnConfig.LEGACY_VPN.equals(packageName)) { + return true; + } + PackageManager pm = mContext.getPackageManager(); + try { + ApplicationInfo appInfo = + pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle); + return appInfo.targetSdkVersion >= VERSION_CODES.Q; + } catch (NameNotFoundException unused) { + Log.w(TAG, "Can't find \"" + packageName + "\""); + return false; + } + } + public NetworkInfo getNetworkInfo() { return mNetworkInfo; } @@ -1038,6 +1099,8 @@ public class Vpn { // as rules are deleted. This prevents data leakage as the rules are moved over. agentDisconnect(oldNetworkAgent); } + // Set up VPN's capabilities such as meteredness. + updateCapabilities(); if (oldConnection != null) { mContext.unbindService(oldConnection); @@ -1249,9 +1312,10 @@ public class Vpn { } /** - * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN - * service app itself, to only sockets that have had {@code protect()} called on them. All - * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel. + * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN + * service app itself and whitelisted packages, to only sockets that have had {@code protect()} + * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the + * kernel. * * The exception for the VPN UID isn't technically necessary -- setup should use protected * sockets -- but in practice it saves apps that don't protect their sockets from breaking. @@ -1267,8 +1331,13 @@ public class Vpn { */ @GuardedBy("this") private void setVpnForcedLocked(boolean enforce) { - final List<String> exemptedPackages = - isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage); + final List<String> exemptedPackages; + if (isNullOrLegacyVpn(mPackage)) { + exemptedPackages = null; + } else { + exemptedPackages = new ArrayList<>(mLockdownWhitelist); + exemptedPackages.add(mPackage); + } final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers); Set<UidRange> addedRanges = Collections.emptySet(); @@ -1732,6 +1801,7 @@ public class Vpn { config.user = profile.key; config.interfaze = iface; config.session = profile.name; + config.isMetered = false; config.addLegacyRoutes(profile.routes); if (!profile.dnsServers.isEmpty()) { diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS index 3c9bbf8797ea..426f002ad236 100644 --- a/services/core/java/com/android/server/dreams/OWNERS +++ b/services/core/java/com/android/server/dreams/OWNERS @@ -1,3 +1,3 @@ -dsandler@google.com +dsandler@android.com michaelwr@google.com roosa@google.com diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 0b7c5b943e5e..64641b3ab8b5 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -1596,6 +1596,7 @@ public class JobSchedulerService extends com.android.server.SystemService } } break; case MSG_CHECK_JOB: + removeMessages(MSG_CHECK_JOB); if (mReportedActive) { // if jobs are currently being run, queue all ready jobs for execution. queueReadyJobsForExecutionLocked(); @@ -1652,7 +1653,6 @@ public class JobSchedulerService extends com.android.server.SystemService } maybeRunPendingJobsLocked(); // Don't remove JOB_EXPIRED in case one came along while processing the queue. - removeMessages(MSG_CHECK_JOB); } } } diff --git a/services/core/java/com/android/server/location/OWNERS b/services/core/java/com/android/server/location/OWNERS index 92b4d5fea113..c2c95e6042de 100644 --- a/services/core/java/com/android/server/location/OWNERS +++ b/services/core/java/com/android/server/location/OWNERS @@ -1,6 +1,8 @@ +aadmal@google.com arthuri@google.com bduddie@google.com gomo@google.com sooniln@google.com weiwa@google.com wyattriley@google.com +yuhany@google.com diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 60d792530101..33b8641c145e 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -51,6 +51,8 @@ per-file UserManagerService.java = omakoto@google.com per-file UserManagerService.java = yamasani@google.com per-file UserRestrictionsUtils.java = omakoto@google.com per-file UserRestrictionsUtils.java = yamasani@google.com +per-file UserRestrictionsUtils.java = rubinxu@google.com +per-file UserRestrictionsUtils.java = sandness@google.com # security per-file KeySetHandle.java = cbrubaker@google.com diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bf872b7c48f6..894897705d44 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -450,8 +450,7 @@ public class PackageManagerService extends IPackageManager.Stub private static final boolean ENABLE_FREE_CACHE_V2 = SystemProperties.getBoolean("fw.free_cache_v2", true); - private static final boolean PRECOMPILED_LAYOUT_ENABLED = - SystemProperties.getBoolean("view.precompiled_layout_enabled", false); + private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts"; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; @@ -9180,7 +9179,7 @@ public class PackageManagerService extends IPackageManager.Stub pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT; } - if (PRECOMPILED_LAYOUT_ENABLED) { + if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { mArtManagerService.compileLayouts(pkg); } @@ -17747,7 +17746,7 @@ public class PackageManagerService extends IPackageManager.Stub if (performDexopt) { // Compile the layout resources. - if (PRECOMPILED_LAYOUT_ENABLED) { + if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts"); mArtManagerService.compileLayouts(pkg); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 9ca02bad50bd..a6242e16a742 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -16,10 +16,6 @@ package com.android.server.pm; -import com.google.android.collect.Sets; - -import com.android.internal.util.Preconditions; - import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -42,6 +38,10 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.util.Preconditions; + +import com.google.android.collect.Sets; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; @@ -660,6 +660,7 @@ public class UserRestrictionsUtils { case android.provider.Settings.Secure.ALWAYS_ON_VPN_APP: case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN: + case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST: // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn final int appId = UserHandle.getAppId(callingUid); if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 863bfd5ea391..a8be07d76b58 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -480,6 +480,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { final String apkPath = pkg.baseCodePath; final ApplicationInfo appInfo = pkg.applicationInfo; final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; + if (appInfo.isPrivilegedApp()) { + // Privileged apps prefer to load trusted code so they don't use compiled views. + return false; + } Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + ") to " + outDexFile); long callingId = Binder.clearCallingIdentity(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8f5d36abcf2c..31e1e358ee6d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1852,7 +1852,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } AlarmManager getAlarmManager() { - return (AlarmManager) mContext.getSystemService(AlarmManager.class); + return mContext.getSystemService(AlarmManager.class); + } + + ConnectivityManager getConnectivityManager() { + return mContext.getSystemService(ConnectivityManager.class); } IWindowManager getIWindowManager() { @@ -5881,7 +5885,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * @throws UnsupportedOperationException if the package does not support being set as always-on. */ @Override - public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown) + public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown, + List<String> lockdownWhitelist) throws SecurityException { enforceProfileOrDeviceOwner(admin); @@ -5889,11 +5894,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long token = mInjector.binderClearCallingIdentity(); try { if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) { - return false; + Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage); + throw new ServiceSpecificException( + DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage); + } + + if (vpnPackage != null && lockdown && lockdownWhitelist != null) { + for (String packageName : lockdownWhitelist) { + if (!isPackageInstalledForUser(packageName, userId)) { + Slog.w(LOG_TAG, "Non-existent package in VPN whitelist: " + packageName); + throw new ServiceSpecificException( + DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName); + } + } } - ConnectivityManager connectivityManager = (ConnectivityManager) - mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdown)) { + // If some package is uninstalled after the check above, it will be ignored by CM. + if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser( + userId, vpnPackage, lockdown, lockdownWhitelist)) { throw new UnsupportedOperationException(); } } finally { @@ -5903,16 +5920,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public String getAlwaysOnVpnPackage(ComponentName admin) + public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException { + enforceProfileOrDeviceOwner(admin); + + final int userId = mInjector.userHandleGetCallingUserId(); + final long token = mInjector.binderClearCallingIdentity(); + try { + return mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId); + } finally { + mInjector.binderRestoreCallingIdentity(token); + } + } + + @Override + public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException { + enforceProfileOrDeviceOwner(admin); + + final int userId = mInjector.userHandleGetCallingUserId(); + final long token = mInjector.binderClearCallingIdentity(); + try { + return mInjector.getConnectivityManager().isVpnLockdownEnabled(userId); + } finally { + mInjector.binderRestoreCallingIdentity(token); + } + } + + @Override + public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin) throws SecurityException { enforceProfileOrDeviceOwner(admin); final int userId = mInjector.userHandleGetCallingUserId(); final long token = mInjector.binderClearCallingIdentity(); - try{ - ConnectivityManager connectivityManager = (ConnectivityManager) - mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - return connectivityManager.getAlwaysOnVpnPackageForUser(userId); + try { + return mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId); } finally { mInjector.binderRestoreCallingIdentity(token); } @@ -6382,9 +6423,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } long token = mInjector.binderClearCallingIdentity(); try { - ConnectivityManager connectivityManager = (ConnectivityManager) - mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - connectivityManager.setGlobalProxy(proxyInfo); + mInjector.getConnectivityManager().setGlobalProxy(proxyInfo); } finally { mInjector.binderRestoreCallingIdentity(token); } diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java index e99dd4f1cbae..bbecc6359a40 100644 --- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java +++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java @@ -16,6 +16,9 @@ package com.android.server.net.ipmemorystore; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentValues; @@ -27,7 +30,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQuery; -import android.net.NetworkUtils; import android.net.ipmemorystore.NetworkAttributes; import android.net.ipmemorystore.Status; import android.util.Log; @@ -200,7 +202,7 @@ public class IpMemoryStoreDatabase { if (null == attributes) return values; if (null != attributes.assignedV4Address) { values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, - NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address)); + inet4AddressToIntHTH(attributes.assignedV4Address)); } if (null != attributes.groupHint) { values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint); @@ -254,7 +256,7 @@ public class IpMemoryStoreDatabase { getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES); final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1); if (0 != assignedV4AddressInt) { - builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt)); + builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt)); } builder.setGroupHint(groupHint); if (null != dnsAddressesBlob) { diff --git a/services/net/Android.bp b/services/net/Android.bp index 30c7de57b73e..638ec95ec544 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -9,12 +9,6 @@ filegroup { "java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering "java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer "java/android/net/shared/*.java", - ], -} - -java_library { - name: "services-netlink-lib", - srcs: [ "java/android/net/netlink/*.java", - ] + ], } diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java index f068c3ac16e2..1fe2328f1cdb 100644 --- a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -16,7 +16,7 @@ package android.net.dhcp; -import static android.net.NetworkUtils.inet4AddressToIntHTH; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import android.annotation.NonNull; import android.net.LinkAddress; diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java index b3af67cdbdc3..970bc9cf667b 100644 --- a/services/net/java/android/net/ip/InterfaceController.java +++ b/services/net/java/android/net/ip/InterfaceController.java @@ -17,7 +17,6 @@ package android.net.ip; import android.net.INetd; -import android.net.InterfaceConfiguration; import android.net.InterfaceConfigurationParcel; import android.net.LinkAddress; import android.net.util.SharedLog; @@ -49,14 +48,18 @@ public class InterfaceController { mLog = log; } - private boolean setInterfaceConfig(InterfaceConfiguration config) { - final InterfaceConfigurationParcel cfgParcel = config.toParcel(mIfName); - + private boolean setInterfaceAddress(LinkAddress addr) { + final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); + ifConfig.ifName = mIfName; + ifConfig.ipv4Addr = addr.getAddress().getHostAddress(); + ifConfig.prefixLength = addr.getPrefixLength(); + ifConfig.hwAddr = ""; + ifConfig.flags = new String[0]; try { - mNetd.interfaceSetCfg(cfgParcel); + mNetd.interfaceSetCfg(ifConfig); } catch (RemoteException | ServiceSpecificException e) { logError("Setting IPv4 address to %s/%d failed: %s", - cfgParcel.ipv4Addr, cfgParcel.prefixLength, e); + ifConfig.ipv4Addr, ifConfig.prefixLength, e); return false; } return true; @@ -69,18 +72,14 @@ public class InterfaceController { if (!(address.getAddress() instanceof Inet4Address)) { return false; } - final InterfaceConfiguration ifConfig = new InterfaceConfiguration(); - ifConfig.setLinkAddress(address); - return setInterfaceConfig(ifConfig); + return setInterfaceAddress(address); } /** * Clear the IPv4Address of the interface. */ public boolean clearIPv4Address() { - final InterfaceConfiguration ifConfig = new InterfaceConfiguration(); - ifConfig.setLinkAddress(new LinkAddress("0.0.0.0/0")); - return setInterfaceConfig(ifConfig); + return setInterfaceAddress(new LinkAddress("0.0.0.0/0")); } private boolean setEnableIPv6(boolean enabled) { diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java deleted file mode 100644 index a61c2efd64da..000000000000 --- a/services/net/java/android/net/ip/IpClient.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.ip; - -import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable; - -import android.content.Context; -import android.net.LinkProperties; -import android.net.Network; -import android.net.ProxyInfo; -import android.net.StaticIpConfiguration; -import android.net.apf.ApfCapabilities; -import android.os.ConditionVariable; -import android.os.INetworkManagementService; -import android.os.RemoteException; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Proxy for the IpClient in the NetworkStack. To be removed once clients are migrated. - * @hide - */ -public class IpClient { - private static final String TAG = IpClient.class.getSimpleName(); - private static final int IPCLIENT_BLOCK_TIMEOUT_MS = 10_000; - - public static final String DUMP_ARG = "ipclient"; - - private final ConditionVariable mIpClientCv; - private final ConditionVariable mShutdownCv; - - private volatile IIpClient mIpClient; - - /** - * @see IpClientCallbacks - */ - public static class Callback extends IpClientCallbacks {} - - /** - * IpClient callback that allows clients to block until provisioning is complete. - */ - public static class WaitForProvisioningCallback extends Callback { - private final ConditionVariable mCV = new ConditionVariable(); - private LinkProperties mCallbackLinkProperties; - - /** - * Block until either {@link #onProvisioningSuccess(LinkProperties)} or - * {@link #onProvisioningFailure(LinkProperties)} is called. - */ - public LinkProperties waitForProvisioning() { - mCV.block(); - return mCallbackLinkProperties; - } - - @Override - public void onProvisioningSuccess(LinkProperties newLp) { - mCallbackLinkProperties = newLp; - mCV.open(); - } - - @Override - public void onProvisioningFailure(LinkProperties newLp) { - mCallbackLinkProperties = null; - mCV.open(); - } - } - - private class CallbackImpl extends IpClientUtil.IpClientCallbacksProxy { - /** - * Create a new IpClientCallbacksProxy. - */ - CallbackImpl(IpClientCallbacks cb) { - super(cb); - } - - @Override - public void onIpClientCreated(IIpClient ipClient) { - mIpClient = ipClient; - mIpClientCv.open(); - super.onIpClientCreated(ipClient); - } - - @Override - public void onQuit() { - mShutdownCv.open(); - super.onQuit(); - } - } - - /** - * Create a new IpClient. - */ - public IpClient(Context context, String iface, Callback callback) { - mIpClientCv = new ConditionVariable(false); - mShutdownCv = new ConditionVariable(false); - - IpClientUtil.makeIpClient(context, iface, new CallbackImpl(callback)); - } - - /** - * @see IpClient#IpClient(Context, String, IpClient.Callback) - */ - public IpClient(Context context, String iface, Callback callback, - INetworkManagementService nms) { - this(context, iface, callback); - } - - private interface IpClientAction { - void useIpClient(IIpClient ipClient) throws RemoteException; - } - - private void doWithIpClient(IpClientAction action) { - mIpClientCv.block(IPCLIENT_BLOCK_TIMEOUT_MS); - try { - action.useIpClient(mIpClient); - } catch (RemoteException e) { - Log.e(TAG, "Error communicating with IpClient", e); - } - } - - /** - * Notify IpClient that PreDhcpAction is completed. - */ - public void completedPreDhcpAction() { - doWithIpClient(c -> c.completedPreDhcpAction()); - } - - /** - * Confirm the provisioning configuration. - */ - public void confirmConfiguration() { - doWithIpClient(c -> c.confirmConfiguration()); - } - - /** - * Notify IpClient that packet filter read is complete. - */ - public void readPacketFilterComplete(byte[] data) { - doWithIpClient(c -> c.readPacketFilterComplete(data)); - } - - /** - * Shutdown the IpClient altogether. - */ - public void shutdown() { - doWithIpClient(c -> c.shutdown()); - } - - /** - * Start the IpClient provisioning. - */ - public void startProvisioning(ProvisioningConfiguration config) { - doWithIpClient(c -> c.startProvisioning(config.toStableParcelable())); - } - - /** - * Stop the IpClient. - */ - public void stop() { - doWithIpClient(c -> c.stop()); - } - - /** - * Set the IpClient TCP buffer sizes. - */ - public void setTcpBufferSizes(String tcpBufferSizes) { - doWithIpClient(c -> c.setTcpBufferSizes(tcpBufferSizes)); - } - - /** - * Set the IpClient HTTP proxy. - */ - public void setHttpProxy(ProxyInfo proxyInfo) { - doWithIpClient(c -> c.setHttpProxy(toStableParcelable(proxyInfo))); - } - - /** - * Set the IpClient multicast filter. - */ - public void setMulticastFilter(boolean enabled) { - doWithIpClient(c -> c.setMulticastFilter(enabled)); - } - - /** - * Dump IpClient logs. - */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - doWithIpClient(c -> IpClientUtil.dumpIpClient(c, fd, pw, args)); - } - - /** - * Block until IpClient shutdown. - */ - public void awaitShutdown() { - mShutdownCv.block(IPCLIENT_BLOCK_TIMEOUT_MS); - } - - /** - * Create a new ProvisioningConfiguration. - */ - public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() { - return new ProvisioningConfiguration.Builder(); - } - - /** - * TODO: remove after migrating clients to use the shared configuration class directly. - * @see android.net.shared.ProvisioningConfiguration - */ - public static class ProvisioningConfiguration - extends android.net.shared.ProvisioningConfiguration { - public ProvisioningConfiguration(android.net.shared.ProvisioningConfiguration other) { - super(other); - } - - /** - * @see android.net.shared.ProvisioningConfiguration.Builder - */ - public static class Builder extends android.net.shared.ProvisioningConfiguration.Builder { - // Override all methods to have a return type matching this Builder - @Override - public Builder withoutIPv4() { - super.withoutIPv4(); - return this; - } - - @Override - public Builder withoutIPv6() { - super.withoutIPv6(); - return this; - } - - @Override - public Builder withoutMultinetworkPolicyTracker() { - super.withoutMultinetworkPolicyTracker(); - return this; - } - - @Override - public Builder withoutIpReachabilityMonitor() { - super.withoutIpReachabilityMonitor(); - return this; - } - - @Override - public Builder withPreDhcpAction() { - super.withPreDhcpAction(); - return this; - } - - @Override - public Builder withPreDhcpAction(int dhcpActionTimeoutMs) { - super.withPreDhcpAction(dhcpActionTimeoutMs); - return this; - } - - @Override - public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) { - super.withStaticConfiguration(staticConfig); - return this; - } - - @Override - public Builder withApfCapabilities(ApfCapabilities apfCapabilities) { - super.withApfCapabilities(apfCapabilities); - return this; - } - - @Override - public Builder withProvisioningTimeoutMs(int timeoutMs) { - super.withProvisioningTimeoutMs(timeoutMs); - return this; - } - - @Override - public Builder withRandomMacAddress() { - super.withRandomMacAddress(); - return this; - } - - @Override - public Builder withStableMacAddress() { - super.withStableMacAddress(); - return this; - } - - @Override - public Builder withNetwork(Network network) { - super.withNetwork(network); - return this; - } - - @Override - public Builder withDisplayName(String displayName) { - super.withDisplayName(displayName); - return this; - } - - @Override - public ProvisioningConfiguration build() { - return new ProvisioningConfiguration(mConfig); - } - } - } -} diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java index f7360f52225f..7910c9a69310 100644 --- a/services/net/java/android/net/ip/IpServer.java +++ b/services/net/java/android/net/ip/IpServer.java @@ -40,7 +40,7 @@ import android.net.dhcp.IDhcpServer; import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; -import android.net.shared.NetdService; +import android.net.util.NetdService; import android.net.util.SharedLog; import android.os.INetworkManagementService; import android.os.Looper; diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java index 2a98d90e5577..16f72bd53e15 100644 --- a/services/net/java/android/net/netlink/NetlinkSocket.java +++ b/services/net/java/android/net/netlink/NetlinkSocket.java @@ -27,14 +27,13 @@ import static android.system.OsConstants.SO_RCVBUF; import static android.system.OsConstants.SO_RCVTIMEO; import static android.system.OsConstants.SO_SNDTIMEO; +import android.net.util.SocketUtils; import android.system.ErrnoException; import android.system.Os; -import android.system.StructTimeval; import android.util.Log; -import libcore.io.IoUtils; - import java.io.FileDescriptor; +import java.io.IOException; import java.io.InterruptedIOException; import java.net.SocketException; import java.nio.ByteBuffer; @@ -95,7 +94,11 @@ public class NetlinkSocket { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, EIO, e); } finally { - IoUtils.closeQuietly(fd); + try { + SocketUtils.closeSocket(fd); + } catch (IOException e) { + // Nothing we can do here + } } } @@ -106,7 +109,7 @@ public class NetlinkSocket { } public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { - Os.connect(fd, makeNetlinkSocketAddress(0, 0)); + SocketUtils.connectSocket(fd, makeNetlinkSocketAddress(0, 0)); } private static void checkTimeout(long timeoutMs) { @@ -125,7 +128,7 @@ public class NetlinkSocket { throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); + SocketUtils.setSocketTimeValueOption(fd, SOL_SOCKET, SO_RCVTIMEO, timeoutMs); ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); int length = Os.read(fd, byteBuffer); @@ -148,7 +151,7 @@ public class NetlinkSocket { FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); + SocketUtils.setSocketTimeValueOption(fd, SOL_SOCKET, SO_SNDTIMEO, timeoutMs); return Os.write(fd, bytes, offset, count); } } diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java index bc2373f4aabc..4ad71381da04 100644 --- a/services/net/java/android/net/shared/InitialConfiguration.java +++ b/services/net/java/android/net/shared/InitialConfiguration.java @@ -20,6 +20,7 @@ import static android.net.shared.ParcelableUtil.fromParcelableArray; import static android.net.shared.ParcelableUtil.toParcelableArray; import static android.text.TextUtils.join; +import android.net.InetAddresses; import android.net.InitialConfigurationParcelable; import android.net.IpPrefix; import android.net.IpPrefixParcelable; @@ -27,7 +28,7 @@ import android.net.LinkAddress; import android.net.LinkAddressParcelable; import android.net.RouteInfo; -import java.net.Inet6Address; +import java.net.Inet4Address; import java.net.InetAddress; import java.util.HashSet; import java.util.List; @@ -43,6 +44,8 @@ public class InitialConfiguration { private static final int RFC6177_MIN_PREFIX_LENGTH = 48; private static final int RFC7421_PREFIX_LENGTH = 64; + public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::"); + /** * Create a InitialConfiguration that is a copy of the specified configuration. */ @@ -102,7 +105,7 @@ public class InitialConfiguration { return false; } // There no more than one IPv4 address - if (ipAddresses.stream().filter(LinkAddress::isIPv4).count() > 1) { + if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) { return false; } @@ -184,11 +187,11 @@ public class InitialConfiguration { } private static boolean isPrefixLengthCompliant(LinkAddress addr) { - return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength()); + return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength()); } private static boolean isPrefixLengthCompliant(IpPrefix prefix) { - return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); + return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); } private static boolean isCompliantIPv6PrefixLength(int prefixLength) { @@ -196,8 +199,16 @@ public class InitialConfiguration { && (prefixLength <= RFC7421_PREFIX_LENGTH); } + private static boolean isIPv4(IpPrefix prefix) { + return prefix.getAddress() instanceof Inet4Address; + } + + private static boolean isIPv4(LinkAddress addr) { + return addr.getAddress() instanceof Inet4Address; + } + private static boolean isIPv6DefaultRoute(IpPrefix prefix) { - return prefix.getAddress().equals(Inet6Address.ANY); + return prefix.getAddress().equals(INET6_ANY); } private static boolean isIPv6GUA(LinkAddress addr) { diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java index 2c368c81523e..1f0525e4da88 100644 --- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java +++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java @@ -44,11 +44,11 @@ public final class IpConfigurationParcelableUtil { @Nullable StaticIpConfiguration config) { if (config == null) return null; final StaticIpConfigurationParcelable p = new StaticIpConfigurationParcelable(); - p.ipAddress = LinkPropertiesParcelableUtil.toStableParcelable(config.ipAddress); - p.gateway = parcelAddress(config.gateway); + p.ipAddress = LinkPropertiesParcelableUtil.toStableParcelable(config.getIpAddress()); + p.gateway = parcelAddress(config.getGateway()); p.dnsServers = toParcelableArray( - config.dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class); - p.domains = config.domains; + config.getDnsServers(), IpConfigurationParcelableUtil::parcelAddress, String.class); + p.domains = config.getDomains(); return p; } @@ -59,11 +59,13 @@ public final class IpConfigurationParcelableUtil { @Nullable StaticIpConfigurationParcelable p) { if (p == null) return null; final StaticIpConfiguration config = new StaticIpConfiguration(); - config.ipAddress = LinkPropertiesParcelableUtil.fromStableParcelable(p.ipAddress); - config.gateway = unparcelAddress(p.gateway); - config.dnsServers.addAll(fromParcelableArray( - p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)); - config.domains = p.domains; + config.setIpAddress(LinkPropertiesParcelableUtil.fromStableParcelable(p.ipAddress)); + config.setGateway(unparcelAddress(p.gateway)); + for (InetAddress addr : fromParcelableArray( + p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)) { + config.addDnsServer(addr); + } + config.setDomains(p.domains); return config; } @@ -73,7 +75,7 @@ public final class IpConfigurationParcelableUtil { public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) { if (results == null) return null; final DhcpResultsParcelable p = new DhcpResultsParcelable(); - p.baseConfiguration = toStableParcelable((StaticIpConfiguration) results); + p.baseConfiguration = toStableParcelable(results.toStaticIpConfiguration()); p.leaseDuration = results.leaseDuration; p.mtu = results.mtu; p.serverAddress = parcelAddress(results.serverAddress); diff --git a/services/net/java/android/net/shared/NetworkObserverRegistry.java b/services/net/java/android/net/shared/NetworkObserverRegistry.java deleted file mode 100644 index 36945f5de2c5..000000000000 --- a/services/net/java/android/net/shared/NetworkObserverRegistry.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.shared; - -import static android.Manifest.permission.NETWORK_STACK; - -import android.content.Context; -import android.net.INetd; -import android.net.INetdUnsolicitedEventListener; -import android.net.INetworkManagementEventObserver; -import android.net.InetAddresses; -import android.net.IpPrefix; -import android.net.LinkAddress; -import android.net.RouteInfo; -import android.os.Handler; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.os.SystemClock; - -/** - * A class for reporting network events to clients. - * - * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to - * all INetworkManagementEventObserver objects that have registered with it. - * - * TODO: Make the notifyXyz methods protected once subclasses (e.g., the NetworkManagementService - * subclass) no longer call them directly. - * - * TODO: change from RemoteCallbackList to direct in-process callbacks. - */ -public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub { - - private final Context mContext; - private final Handler mDaemonHandler; - private static final String TAG = "NetworkObserverRegistry"; - - /** - * Constructs a new instance and registers it with netd. - * This method should only be called once since netd will reject multiple registrations from - * the same process. - */ - public NetworkObserverRegistry(Context context, Handler handler, INetd netd) - throws RemoteException { - mContext = context; - mDaemonHandler = handler; - netd.registerUnsolicitedEventListener(this); - } - - private final RemoteCallbackList<INetworkManagementEventObserver> mObservers = - new RemoteCallbackList<>(); - - /** - * Registers the specified observer and start sending callbacks to it. - * This method may be called on any thread. - */ - public void registerObserver(INetworkManagementEventObserver observer) { - mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG); - mObservers.register(observer); - } - - /** - * Unregisters the specified observer and stop sending callbacks to it. - * This method may be called on any thread. - */ - public void unregisterObserver(INetworkManagementEventObserver observer) { - mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG); - mObservers.unregister(observer); - } - - @FunctionalInterface - private interface NetworkManagementEventCallback { - void sendCallback(INetworkManagementEventObserver o) throws RemoteException; - } - - private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) { - final int length = mObservers.beginBroadcast(); - try { - for (int i = 0; i < length; i++) { - try { - eventCallback.sendCallback(mObservers.getBroadcastItem(i)); - } catch (RemoteException | RuntimeException e) { - } - } - } finally { - mObservers.finishBroadcast(); - } - } - - /** - * Notify our observers of a change in the data activity state of the interface - */ - public void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos, - int uid, boolean fromRadio) { - invokeForAllObservers(o -> o.interfaceClassDataActivityChanged( - Integer.toString(type), isActive, tsNanos)); - } - - @Override - public void onInterfaceClassActivityChanged(boolean isActive, - int label, long timestamp, int uid) throws RemoteException { - final long timestampNanos; - if (timestamp <= 0) { - timestampNanos = SystemClock.elapsedRealtimeNanos(); - } else { - timestampNanos = timestamp; - } - mDaemonHandler.post(() -> notifyInterfaceClassActivity(label, isActive, - timestampNanos, uid, false)); - } - - /** - * Notify our observers of a limit reached. - */ - @Override - public void onQuotaLimitReached(String alertName, String ifName) throws RemoteException { - mDaemonHandler.post(() -> notifyLimitReached(alertName, ifName)); - } - - /** - * Notify our observers of a limit reached. - */ - public void notifyLimitReached(String limitName, String iface) { - invokeForAllObservers(o -> o.limitReached(limitName, iface)); - } - - @Override - public void onInterfaceDnsServerInfo(String ifName, - long lifetime, String[] servers) throws RemoteException { - mDaemonHandler.post(() -> notifyInterfaceDnsServerInfo(ifName, lifetime, servers)); - } - - /** - * Notify our observers of DNS server information received. - */ - public void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) { - invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses)); - } - - @Override - public void onInterfaceAddressUpdated(String addr, - String ifName, int flags, int scope) throws RemoteException { - final LinkAddress address = new LinkAddress(addr, flags, scope); - mDaemonHandler.post(() -> notifyAddressUpdated(ifName, address)); - } - - /** - * Notify our observers of a new or updated interface address. - */ - public void notifyAddressUpdated(String iface, LinkAddress address) { - invokeForAllObservers(o -> o.addressUpdated(iface, address)); - } - - @Override - public void onInterfaceAddressRemoved(String addr, - String ifName, int flags, int scope) throws RemoteException { - final LinkAddress address = new LinkAddress(addr, flags, scope); - mDaemonHandler.post(() -> notifyAddressRemoved(ifName, address)); - } - - /** - * Notify our observers of a deleted interface address. - */ - public void notifyAddressRemoved(String iface, LinkAddress address) { - invokeForAllObservers(o -> o.addressRemoved(iface, address)); - } - - - @Override - public void onInterfaceAdded(String ifName) throws RemoteException { - mDaemonHandler.post(() -> notifyInterfaceAdded(ifName)); - } - - /** - * Notify our observers of an interface addition. - */ - public void notifyInterfaceAdded(String iface) { - invokeForAllObservers(o -> o.interfaceAdded(iface)); - } - - @Override - public void onInterfaceRemoved(String ifName) throws RemoteException { - mDaemonHandler.post(() -> notifyInterfaceRemoved(ifName)); - } - - /** - * Notify our observers of an interface removal. - */ - public void notifyInterfaceRemoved(String iface) { - invokeForAllObservers(o -> o.interfaceRemoved(iface)); - } - - @Override - public void onInterfaceChanged(String ifName, boolean up) throws RemoteException { - mDaemonHandler.post(() -> notifyInterfaceStatusChanged(ifName, up)); - } - - /** - * Notify our observers of an interface status change - */ - public void notifyInterfaceStatusChanged(String iface, boolean up) { - invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up)); - } - - @Override - public void onInterfaceLinkStateChanged(String ifName, boolean up) throws RemoteException { - mDaemonHandler.post(() -> notifyInterfaceLinkStateChanged(ifName, up)); - } - - /** - * Notify our observers of an interface link state change - * (typically, an Ethernet cable has been plugged-in or unplugged). - */ - public void notifyInterfaceLinkStateChanged(String iface, boolean up) { - invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up)); - } - - @Override - public void onRouteChanged(boolean updated, - String route, String gateway, String ifName) throws RemoteException { - final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), - ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), - ifName); - mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute)); - } - - /** - * Notify our observers of a route change. - */ - public void notifyRouteChange(boolean updated, RouteInfo route) { - if (updated) { - invokeForAllObservers(o -> o.routeUpdated(route)); - } else { - invokeForAllObservers(o -> o.routeRemoved(route)); - } - } - - @Override - public void onStrictCleartextDetected(int uid, String hex) throws RemoteException { - // Don't do anything here because this is not a method of INetworkManagementEventObserver. - // Only the NMS subclass will implement this. - } -} diff --git a/services/net/java/android/net/shared/NetdService.java b/services/net/java/android/net/util/NetdService.java index be0f5f2d4f34..d4cd5bd7ba18 100644 --- a/services/net/java/android/net/shared/NetdService.java +++ b/services/net/java/android/net/util/NetdService.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package android.net.shared; +package android.net.util; +import android.content.Context; import android.net.INetd; import android.os.RemoteException; import android.os.ServiceManager; @@ -28,7 +29,6 @@ import android.util.Log; */ public class NetdService { private static final String TAG = NetdService.class.getSimpleName(); - private static final String NETD_SERVICE_NAME = "netd"; private static final long BASE_TIMEOUT_MS = 100; private static final long MAX_TIMEOUT_MS = 1000; @@ -48,7 +48,7 @@ public class NetdService { // NOTE: ServiceManager does no caching for the netd service, // because netd is not one of the defined common services. final INetd netdInstance = INetd.Stub.asInterface( - ServiceManager.getService(NETD_SERVICE_NAME)); + ServiceManager.getService(Context.NETD_SERVICE)); if (netdInstance == null) { Log.w(TAG, "WARNING: returning null INetd instance."); } diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 84611667d113..39fc715c7770 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -124,6 +124,7 @@ public class AppStandbyControllerTests { static class MyInjector extends AppStandbyController.Injector { long mElapsedRealtime; + boolean mIsAppIdleEnabled = true; boolean mIsCharging; List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>(); boolean mDisplayOn; @@ -155,7 +156,7 @@ public class AppStandbyControllerTests { @Override boolean isAppIdleEnabled() { - return true; + return mIsAppIdleEnabled; } @Override @@ -266,6 +267,13 @@ public class AppStandbyControllerTests { } } + private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) { + mInjector.mIsAppIdleEnabled = enabled; + if (controller != null) { + controller.setAppIdleEnabled(enabled); + } + } + private AppStandbyController setupController() throws Exception { mInjector.mElapsedRealtime = 0; setupPm(mInjector.getContext().getPackageManager()); @@ -335,7 +343,7 @@ public class AppStandbyControllerTests { public void onParoleStateChanged(boolean isParoleOn) { synchronized (this) { // Only record information if it is being looked for - if (mLatch.getCount() > 0) { + if (mLatch != null && mLatch.getCount() > 0) { mOnParole = isParoleOn; mLastParoleChangeTime = getCurrentTime(); mLatch.countDown(); @@ -396,6 +404,74 @@ public class AppStandbyControllerTests { marginOfError); } + @Test + public void testEnabledState() throws Exception { + TestParoleListener paroleListener = new TestParoleListener(); + mController.addListener(paroleListener); + long lastUpdateTime; + + // Test that listeners are notified if enabled changes when the device is not in parole. + setChargingState(mController, false); + + // Start off not enabled. Device is effectively on permanent parole. + setAppIdleEnabled(mController, false); + + // Enable controller + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, true); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertFalse(paroleListener.mOnParole); + lastUpdateTime = paroleListener.getLastParoleChangeTime(); + + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, true); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertFalse(paroleListener.mOnParole); + // Make sure AppStandbyController doesn't notify listeners when there's no change. + assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime()); + + // Disable controller + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, false); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertTrue(paroleListener.mOnParole); + lastUpdateTime = paroleListener.getLastParoleChangeTime(); + + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, false); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertTrue(paroleListener.mOnParole); + // Make sure AppStandbyController doesn't notify listeners when there's no change. + assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime()); + + + // Test that listeners aren't notified if enabled status changes when the device is already + // in parole. + + // A device is in parole whenever it's charging. + setChargingState(mController, true); + + // Start off not enabled. + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, false); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertTrue(paroleListener.mOnParole); + lastUpdateTime = paroleListener.getLastParoleChangeTime(); + + // Test that toggling doesn't notify the listener. + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, true); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertTrue(paroleListener.mOnParole); + assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime()); + + paroleListener.rearmLatch(); + setAppIdleEnabled(mController, false); + paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2); + assertTrue(paroleListener.mOnParole); + assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime()); + } + private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) { mInjector.mElapsedRealtime = elapsedTime; controller.checkIdleStates(USER_ID); diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index 9c62700a9118..e380d7a6808b 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -30,18 +30,19 @@ import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN; +import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED; +import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; -import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED; -import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET; + import static com.android.server.SystemService.PHASE_BOOT_COMPLETED; import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; @@ -340,14 +341,21 @@ public class AppStandbyController { } void setAppIdleEnabled(boolean enabled) { - mAppIdleEnabled = enabled; + synchronized (mAppIdleLock) { + if (mAppIdleEnabled != enabled) { + final boolean oldParoleState = isParoledOrCharging(); + mAppIdleEnabled = enabled; + if (isParoledOrCharging() != oldParoleState) { + postParoleStateChanged(); + } + } + } } public void onBootPhase(int phase) { mInjector.onBootPhase(phase); if (phase == PHASE_SYSTEM_SERVICES_READY) { Slog.d(TAG, "Setting app idle enabled state"); - setAppIdleEnabled(mInjector.isAppIdleEnabled()); // Observe changes to the threshold SettingsObserver settingsObserver = new SettingsObserver(mHandler); settingsObserver.registerObserver(); @@ -1807,8 +1815,6 @@ public class AppStandbyController { mContext.getContentResolver(), Global.APP_IDLE_CONSTANTS)); } - // Check if app_idle_enabled has changed - setAppIdleEnabled(mInjector.isAppIdleEnabled()); // Look at global settings for this. // TODO: Maybe apply different thresholds for different users. @@ -1880,6 +1886,10 @@ public class AppStandbyController { (KEY_STABLE_CHARGING_THRESHOLD, COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD); } + + // Check if app_idle_enabled has changed. Do this after getting the rest of the settings + // in case we need to change something based on the new values. + setAppIdleEnabled(mInjector.isAppIdleEnabled()); } long[] parseLongArray(String values, long[] defaults) { diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index 7dc83c3db868..f5b4308a1b50 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -16,12 +16,12 @@ cc_defaults { name: "viewcompiler_defaults", + defaults: ["libdexfile_static_defaults"], header_libs: [ "libbase_headers", ], shared_libs: [ "libbase", - "libdexfile", "libz", "slicer", ], diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 2820836282a1..dcaa49996d0b 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -239,6 +239,30 @@ public final class Call { "android.telecom.event.HANDOVER_FAILED"; public static class Details { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "DIRECTION_" }, + value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING}) + public @interface CallDirection {} + + /** + * Indicates that the call is neither and incoming nor an outgoing call. This can be the + * case for calls reported directly by a {@link ConnectionService} in special cases such as + * call handovers. + */ + public static final int DIRECTION_UNKNOWN = -1; + + /** + * Indicates that the call is an incoming call. + */ + public static final int DIRECTION_INCOMING = 0; + + /** + * Indicates that the call is an outgoing call. + */ + public static final int DIRECTION_OUTGOING = 1; + /** Call can currently be put on hold or unheld. */ public static final int CAPABILITY_HOLD = 0x00000001; @@ -519,6 +543,7 @@ public final class Call { private final Bundle mIntentExtras; private final long mCreationTimeMillis; private final CallIdentification mCallIdentification; + private final @CallDirection int mCallDirection; /** * Whether the supplied capabilities supports the specified capability. @@ -838,6 +863,14 @@ public final class Call { return mCallIdentification; } + /** + * Indicates whether the call is an incoming or outgoing call. + * @return The call's direction. + */ + public @CallDirection int getCallDirection() { + return mCallDirection; + } + @Override public boolean equals(Object o) { if (o instanceof Details) { @@ -859,7 +892,8 @@ public final class Call { areBundlesEqual(mExtras, d.mExtras) && areBundlesEqual(mIntentExtras, d.mIntentExtras) && Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) && - Objects.equals(mCallIdentification, d.mCallIdentification); + Objects.equals(mCallIdentification, d.mCallIdentification) && + Objects.equals(mCallDirection, d.mCallDirection); } return false; } @@ -881,7 +915,8 @@ public final class Call { mExtras, mIntentExtras, mCreationTimeMillis, - mCallIdentification); + mCallIdentification, + mCallDirection); } /** {@hide} */ @@ -902,7 +937,8 @@ public final class Call { Bundle extras, Bundle intentExtras, long creationTimeMillis, - CallIdentification callIdentification) { + CallIdentification callIdentification, + int callDirection) { mTelecomCallId = telecomCallId; mHandle = handle; mHandlePresentation = handlePresentation; @@ -920,6 +956,7 @@ public final class Call { mIntentExtras = intentExtras; mCreationTimeMillis = creationTimeMillis; mCallIdentification = callIdentification; + mCallDirection = callDirection; } /** {@hide} */ @@ -941,7 +978,8 @@ public final class Call { parcelableCall.getExtras(), parcelableCall.getIntentExtras(), parcelableCall.getCreationTimeMillis(), - parcelableCall.getCallIdentification()); + parcelableCall.getCallIdentification(), + parcelableCall.getCallDirection()); } @Override diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java index 97af06c1d64c..87834fd5109d 100644 --- a/telecomm/java/android/telecom/CallIdentification.java +++ b/telecomm/java/android/telecom/CallIdentification.java @@ -250,8 +250,8 @@ public final class CallIdentification implements Parcelable { mDetails = details; mPhoto = photo; mNuisanceConfidence = nuisanceConfidence; - mCallScreeningAppName = callScreeningPackageName; - mCallScreeningPackageName = callScreeningAppName; + mCallScreeningAppName = callScreeningAppName; + mCallScreeningPackageName = callScreeningPackageName; } private String mName; @@ -430,4 +430,22 @@ public final class CallIdentification implements Parcelable { return Objects.hash(mName, mDescription, mDetails, mPhoto, mNuisanceConfidence, mCallScreeningAppName, mCallScreeningPackageName); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[CallId mName="); + sb.append(Log.pii(mName)); + sb.append(", mDesc="); + sb.append(mDescription); + sb.append(", mDet="); + sb.append(mDetails); + sb.append(", conf="); + sb.append(mNuisanceConfidence); + sb.append(", appName="); + sb.append(mCallScreeningAppName); + sb.append(", pkgName="); + sb.append(mCallScreeningPackageName); + return sb.toString(); + } } diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index be96b3cac6f6..826ad82dfbb2 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -21,6 +21,7 @@ import android.annotation.SdkConstant; import android.app.Service; import android.content.ComponentName; import android.content.Intent; +import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -33,8 +34,9 @@ import com.android.internal.telecom.ICallScreeningService; /** * This service can be implemented by the default dialer (see - * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before - * they are shown to a user. + * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow + * incoming calls before they are shown to a user. This service can also provide + * {@link CallIdentification} information for calls. * <p> * Below is an example manifest registration for a {@code CallScreeningService}. * <pre> @@ -56,6 +58,34 @@ import com.android.internal.telecom.ICallScreeningService; * information about a {@link Call.Details call} which will be shown to the user in the * Dialer app.</li> * </ol> + * <p> + * <h2>Becoming the {@link CallScreeningService}</h2> + * Telecom will bind to a single app chosen by the user which implements the + * {@link CallScreeningService} API when there are new incoming and outgoing calls. + * <p> + * The code snippet below illustrates how your app can request that it fills the call screening + * role. + * <pre> + * {@code + * private static final int REQUEST_ID = 1; + * + * public void requestRole() { + * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE); + * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP"); + * startActivityForResult(intent, REQUEST_ID); + * } + * + * @Override + * public void onActivityResult(int requestCode, int resultCode, Intent data) { + * if (requestCode == REQUEST_ID) { + * if (resultCode == android.app.Activity.RESULT_OK) { + * // Your app is now the call screening app + * } else { + * // Your app is not the call screening app + * } + * } + * } + * </pre> */ public abstract class CallScreeningService extends Service { /** @@ -222,30 +252,46 @@ public abstract class CallScreeningService extends Service { } /** - * Called when a new incoming call is added. - * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)} - * should be called to allow or disallow the call. + * Called when a new incoming or outgoing call is added which is not in the user's contact list. + * <p> + * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by + * calling + * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}. + * Your app can tell if a call is an incoming call by checking to see if + * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}. + * <p> + * For incoming or outgoing calls, the {@link CallScreeningService} can call + * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide + * {@link CallIdentification} for the call. * <p> * Note: The {@link Call.Details} instance provided to a call screening service will only have * the following properties set. The rest of the {@link Call.Details} properties will be set to * their default value or {@code null}. * <ul> - * <li>{@link Call.Details#getState()}</li> + * <li>{@link Call.Details#getCallDirection()}</li> * <li>{@link Call.Details#getConnectTimeMillis()}</li> * <li>{@link Call.Details#getCreationTimeMillis()}</li> * <li>{@link Call.Details#getHandle()}</li> * <li>{@link Call.Details#getHandlePresentation()}</li> * </ul> + * <p> + * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme} + * is {@link PhoneAccount#SCHEME_TEL} are passed for call + * screening. Further, only calls which are not in the user's contacts are passed for + * screening. For outgoing calls, no post-dial digits are passed. * - * @param callDetails Information about a new incoming call, see {@link Call.Details}. + * @param callDetails Information about a new call, see {@link Call.Details}. */ public abstract void onScreenCall(@NonNull Call.Details callDetails); /** - * Responds to the given call, either allowing it or disallowing it. + * Responds to the given incoming call, either allowing it or disallowing it. * <p> * The {@link CallScreeningService} calls this method to inform the system whether the call * should be silently blocked or not. + * <p> + * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is + * {@link Call.Details#DIRECTION_INCOMING}. * * @param callDetails The call to allow. * <p> diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 1aeeca73c0b9..cea2fbfa588c 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -40,11 +40,30 @@ import java.util.Collections; import java.util.List; /** - * This service is implemented by any app that wishes to provide the user-interface for managing - * phone calls. Telecom binds to this service while there exists a live (active or incoming) call, - * and uses it to notify the in-call app of any live and recently disconnected calls. An app must - * first be set as the default phone app (See {@link TelecomManager#getDefaultDialerPackage()}) - * before the telecom service will bind to its {@code InCallService} implementation. + * This service is implemented by an app that wishes to provide functionality for managing + * phone calls. + * <p> + * There are three types of apps which Telecom can bind to when there exists a live (active or + * incoming) call: + * <ol> + * <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the + * in-call user interface while the device is in a call. A device is bundled with a system + * provided default dialer/phone app. The user may choose a single app to take over this role + * from the system app.</li> + * <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which + * provides the in-call user interface while the device is in a call and the device is in car + * mode. The user may choose a single app to fill this role.</li> + * <li>Call Companion app - a call companion app is one which provides no user interface itself, + * but exposes call information to another display surface, such as a wearable device. The + * user may choose multiple apps to fill this role.</li> + * </ol> + * <p> + * Apps which wish to fulfill one of the above roles use the {@code android.app.role.RoleManager} + * to request that they fill the desired role. + * + * <h2>Becoming the Default Phone App</h2> + * An app filling the role of the default phone app provides a user interface while the device is in + * a call, and the device is not in car mode. * <p> * Below is an example manifest registration for an {@code InCallService}. The meta-data * {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular @@ -82,12 +101,34 @@ import java.util.List; * } * </pre> * <p> - * When a user installs your application and runs it for the first time, you should prompt the user - * to see if they would like your application to be the new default phone app. See the - * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on - * how to do this. + * When a user installs your application and runs it for the first time, you should use the + * {@code android.app.role.RoleManager} to prompt the user to see if they would like your app to + * be the new default phone app. + * <p id="requestRole"> + * The code below shows how your app can request to become the default phone/dialer app: + * <pre> + * {@code + * private static final int REQUEST_ID = 1; + * + * public void requestRole() { + * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE); + * Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER); + * startActivityForResult(intent, REQUEST_ID); + * } + * + * @Override + * public void onActivityResult(int requestCode, int resultCode, Intent data) { + * if (requestCode == REQUEST_ID) { + * if (resultCode == android.app.Activity.RESULT_OK) { + * // Your app is now the default dialer app + * } else { + * // Your app is not the default dialer app + * } + * } + * } + * </pre> * <p id="incomingCallNotification"> - * <h2>Showing the Incoming Call Notification</h2> + * <h3>Showing the Incoming Call Notification</h3> * When your app receives a new incoming call via {@link InCallService#onCallAdded(Call)}, it is * responsible for displaying an incoming call UI for the incoming call. It should do this using * {@link android.app.NotificationManager} APIs to post a new incoming call notification. @@ -121,7 +162,7 @@ import java.util.List; * heads-up notification if the user is actively using the phone. When the user is not using the * phone, your full-screen incoming call UI is used instead. * For example: - * <pre><code> + * <pre><code>{@code * // Create an intent which triggers your fullscreen incoming call user interface. * Intent intent = new Intent(Intent.ACTION_MAIN, null); * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK); @@ -151,7 +192,49 @@ import java.util.List; * NotificationManager notificationManager = mContext.getSystemService( * NotificationManager.class); * notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build()); - * </code></pre> + * }</pre> + * <p> + * <h2>Becoming the Default Car-mode Phone App</h2> + * An app filling the role of the default car-mode dialer/phone app provides a user interface while + * the device is in a call, and in car mode. See + * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode. + * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead + * of the usual dialer/phone app. + * <p> + * Similar to the requirements for becoming the default dialer/phone app, your app must declare a + * manifest entry for its {@link InCallService} implementation. Your manifest entry should ensure + * the following conditions are met: + * <ul> + * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> + * <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to + * {@code true}<li> + * <li>Your app must request the permission + * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> + * </ul> + * <p> + * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to + * become the default (see <a href="#requestRole">above</a> for how to request your app fills this + * role). + * + * <h2>Becoming a Call Companion App</h2> + * An app which fills the companion app role does not directly provide a user interface while the + * device is in a call. Instead, it is typically used to relay information about calls to another + * display surface, such as a wearable device. + * <p> + * Similar to the requirements for becoming the default dialer/phone app, your app must declare a + * manifest entry for its {@link InCallService} implementation. Your manifest entry should + * ensure the following conditions are met: + * <ul> + * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li> + * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} + * metadata.</li> + * <li>Your app must request the permission + * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li> + * </ul> + * <p> + * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to + * become a call companion app (see <a href="#requestRole">above</a> for how to request your app + * fills this role). */ public abstract class InCallService extends Service { diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 911786e455c2..f7dec83c3ace 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.telecom.Call.Details.CallDirection; import java.util.ArrayList; import java.util.Collections; @@ -64,6 +65,7 @@ public final class ParcelableCall implements Parcelable { private final Bundle mExtras; private final long mCreationTimeMillis; private final CallIdentification mCallIdentification; + private final int mCallDirection; public ParcelableCall( String id, @@ -92,7 +94,8 @@ public final class ParcelableCall implements Parcelable { Bundle intentExtras, Bundle extras, long creationTimeMillis, - CallIdentification callIdentification) { + CallIdentification callIdentification, + int callDirection) { mId = id; mState = state; mDisconnectCause = disconnectCause; @@ -120,6 +123,7 @@ public final class ParcelableCall implements Parcelable { mExtras = extras; mCreationTimeMillis = creationTimeMillis; mCallIdentification = callIdentification; + mCallDirection = callDirection; } /** The unique ID of the call. */ @@ -318,6 +322,13 @@ public final class ParcelableCall implements Parcelable { return mCallIdentification; } + /** + * Indicates whether the call is an incoming or outgoing call. + */ + public @CallDirection int getCallDirection() { + return mCallDirection; + } + /** Responsible for creating ParcelableCall objects for deserialized Parcels. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final Parcelable.Creator<ParcelableCall> CREATOR = @@ -356,6 +367,7 @@ public final class ParcelableCall implements Parcelable { ParcelableRttCall rttCall = source.readParcelable(classLoader); long creationTimeMillis = source.readLong(); CallIdentification callIdentification = source.readParcelable(classLoader); + int callDirection = source.readInt(); return new ParcelableCall( id, state, @@ -383,7 +395,8 @@ public final class ParcelableCall implements Parcelable { intentExtras, extras, creationTimeMillis, - callIdentification); + callIdentification, + callDirection); } @Override @@ -429,6 +442,7 @@ public final class ParcelableCall implements Parcelable { destination.writeParcelable(mRttCall, 0); destination.writeLong(mCreationTimeMillis); destination.writeParcelable(mCallIdentification, 0); + destination.writeInt(mCallDirection); } @Override diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java index 7b2306128b7b..157f12c9f105 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -16,7 +16,9 @@ package android.telecom; +import android.annotation.FloatRange; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -364,7 +366,7 @@ public class VideoProfile implements Parcelable { * @param width The width of the camera video (in pixels). * @param height The height of the camera video (in pixels). */ - public CameraCapabilities(int width, int height) { + public CameraCapabilities(@IntRange(from = 0) int width, @IntRange(from = 0) int height) { this(width, height, false, 1.0f); } @@ -376,7 +378,8 @@ public class VideoProfile implements Parcelable { * @param zoomSupported True when camera supports zoom. * @param maxZoom Maximum zoom supported by camera. */ - public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) { + public CameraCapabilities(@IntRange(from = 0) int width, @IntRange(from = 0) int height, + boolean zoomSupported, @FloatRange(from = 1.0f) float maxZoom) { mWidth = width; mHeight = height; mZoomSupported = zoomSupported; diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java index b27f6b44370f..cbe622847130 100644 --- a/telephony/java/android/telephony/CallQuality.java +++ b/telephony/java/android/telephony/CallQuality.java @@ -92,6 +92,10 @@ public final class CallQuality implements Parcelable { mCodecType = in.readInt(); } + /** @hide **/ + public CallQuality() { + } + /** * Constructor. * diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 26cba773c9cc..190e82b6cc5b 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2371,33 +2371,54 @@ public class CarrierConfigManager { "support_emergency_dialer_shortcut_bool"; /** - * Controls RSRP threshold at which AlternativeNetworkService will decide whether + * Controls RSRP threshold at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int"; /** - * Controls RSSNR threshold at which AlternativeNetworkService will decide whether + * Controls RSSNR threshold at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int"; /** - * Controls RSRP threshold below which AlternativeNetworkService will decide whether + * Controls RSRP threshold below which OpportunisticNetworkService will decide whether * the opportunistic network available is not good enough for internet data. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; /** - * Controls RSSNR threshold below which AlternativeNetworkService will decide whether + * Controls RSSNR threshold below which OpportunisticNetworkService will decide whether * the opportunistic network available is not good enough for internet data. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; + /** + * Controls bandwidth threshold in Kbps at which OpportunisticNetworkService will decide whether + * the opportunistic network is good enough for internet data. + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT = + "opportunistic_network_entry_threshold_bandwidth_int"; + + /** + * Controls hysteresis time in milli seconds for which OpportunisticNetworkService + * will wait before attaching to a network. + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG = + "opportunistic_network_entry_or_exit_hysteresis_time_long"; + + /** + * Controls hysteresis time in milli seconds for which OpportunisticNetworkService + * will wait before switching data to a network. + */ + public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = + "opportunistic_network_data_switch_hysteresis_time_long"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -2767,6 +2788,12 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45); /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10); + /* Default value is 1024 kbps */ + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024); + /* Default value is 10 seconds */ + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000); + /* Default value is 10 seconds. */ + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000); } /** diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java index 4bca404d9444..6c45cc4ef3b8 100644 --- a/telephony/java/android/telephony/NetworkService.java +++ b/telephony/java/android/telephony/NetworkService.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; @@ -112,13 +113,13 @@ public abstract class NetworkService extends Service { mSlotId, 0, null).sendToTarget(); } - private void registerForStateChanged(INetworkServiceCallback callback) { + private void registerForStateChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationStateChangedCallbacks) { mNetworkRegistrationStateChangedCallbacks.add(callback); } } - private void unregisterForStateChanged(INetworkServiceCallback callback) { + private void unregisterForStateChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationStateChangedCallbacks) { mNetworkRegistrationStateChangedCallbacks.remove(callback); } diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 9fee5932dadc..fea1b7b08a20 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -28,6 +28,7 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsReasonInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IPhoneStateListener; @@ -347,6 +348,20 @@ public class PhoneStateListener { @SystemApi public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000; + /** + * Listen for IMS call disconnect causes which contains + * {@link android.telephony.ims.ImsReasonInfo} + * + * {@more} + * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} + * + * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo) + * @hide + */ + @SystemApi + public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 0x08000000; + /* * Subscription used to listen to the phone state changes * @hide @@ -578,6 +593,17 @@ public class PhoneStateListener { } /** + * Callback invoked when Ims call disconnect cause changes. + * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed. + * + * @hide + */ + @SystemApi + public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) { + // default implementation empty + } + + /** * Callback invoked when data connection state changes with precise information. * @param dataConnectionState {@link PreciseDataConnectionState} * @@ -701,7 +727,7 @@ public class PhoneStateListener { * @hide */ @SystemApi - public void onCallAttributesChanged(CallAttributes callAttributes) { + public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) { // default implementation empty } @@ -981,6 +1007,16 @@ public class PhoneStateListener { Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> psl.onPreferredDataSubIdChanged(subId))); } + + public void onImsCallDisconnectCauseChanged(ImsReasonInfo disconnectCause) { + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onImsCallDisconnectCauseChanged(disconnectCause))); + + } } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index bf9bf9a1ba8f..33178766f3a3 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -540,7 +540,7 @@ public class ServiceState implements Parcelable { * * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage public int getDataRegState() { return mDataRegState; } @@ -1631,8 +1631,9 @@ public class ServiceState implements Parcelable { /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) { - return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0; + public static boolean bearerBitmapHasCdma(int networkTypeBitmask) { + return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK + & convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask)) != 0; } /** @hide */ diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 4e4ef4d6c236..443f90844c50 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -577,10 +577,10 @@ public class SubscriptionInfo implements Parcelable { } /** - * @return the cardId of the SIM card which contains the subscription. - * @hide + * Returns the card ID of the SIM card which contains the subscription (see + * {@link UiccCardInfo#getCardId()}. + * @return the cardId */ - @SystemApi public int getCardId() { return this.mCardId; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index b9ffd4d21890..24d790a663c9 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -93,6 +93,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.Executor; import java.util.regex.Matcher; @@ -226,10 +227,9 @@ public class TelephonyManager { public static final int SRVCC_STATE_HANDOVER_CANCELED = 3; /** - * An invalid card identifier. - * @hide + * An invalid UICC card identifier. See {@link #getCardIdForDefaultEuicc()} and + * {@link UiccCardInfo#getCardId()}. */ - @SystemApi public static final int INVALID_CARD_ID = -1; /** @hide */ @@ -349,41 +349,30 @@ public class TelephonyManager { * Returns 0 if none of voice, sms, data is not supported * Returns 1 for Single standby mode (Single SIM functionality) * Returns 2 for Dual standby mode.(Dual SIM functionality) + * Returns 3 for Tri standby mode.(Tri SIM functionality) */ public int getPhoneCount() { - int phoneCount = 1; - switch (getMultiSimConfiguration()) { - case UNKNOWN: - // if voice or sms or data is supported, return 1 otherwise 0 - if (isVoiceCapable() || isSmsCapable()) { - phoneCount = 1; - } else { - // todo: try to clean this up further by getting rid of the nested conditions - if (mContext == null) { - phoneCount = 1; - } else { - // check for data support - ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - if (cm == null) { - phoneCount = 1; - } else { - if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { - phoneCount = 1; - } else { - phoneCount = 0; - } - } - } + int phoneCount = 0; + + // check for voice and data support, 0 if not supported + if (!isVoiceCapable() && !isSmsCapable()) { + ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + if (cm != null) { + if (!cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { + return phoneCount; } - break; - case DSDS: - case DSDA: - phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; - break; - case TSTS: - phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM; - break; + } + } + + phoneCount = 1; + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + phoneCount = telephony.getNumOfActiveSims(); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "getNumOfActiveSims RemoteException", ex); } return phoneCount; } @@ -3117,14 +3106,8 @@ public class TelephonyManager { * unique to a device, and always refer to the same UICC or eUICC card unless the device goes * through a factory reset. * - * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} - * * @return card ID of the default eUICC card. - * @hide */ - @SystemApi - @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCardIdForDefaultEuicc() { try { ITelephony telephony = getITelephony(); @@ -3138,25 +3121,37 @@ public class TelephonyManager { } /** - * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more - * details on the kind of information available. - * - * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the - * currently inserted UICCs and eUICCs. + * Gets information about currently inserted UICCs and enabled eUICCs. + * <p> + * Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * <p> + * If the caller has carrier priviliges on any active subscription, then they have permission to + * get simple information like the card ID ({@link UiccCardInfo#getCardId()}), whether the card + * is an eUICC ({@link UiccCardInfo#isEuicc()}), and the slot index where the card is inserted + * ({@link UiccCardInfo#getSlotIndex()}). + * <p> + * To get private information such as the EID ({@link UiccCardInfo#getEid()}) or ICCID + * ({@link UiccCardInfo#getIccId()}), the caller must have carrier priviliges on that specific + * UICC or eUICC card. + * <p> + * See {@link UiccCardInfo} for more details on the kind of information available. * - * @hide + * @return a list of UiccCardInfo objects, representing information on the currently inserted + * UICCs and eUICCs. Each UiccCardInfo in the list will have private information filtered out if + * the caller does not have adequate permissions for that card. */ - @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public UiccCardInfo[] getUiccCardsInfo() { + public List<UiccCardInfo> getUiccCardsInfo() { try { ITelephony telephony = getITelephony(); if (telephony == null) { - return null; + Log.e(TAG, "Error in getUiccCardsInfo: unable to connect to Telephony service."); + return new ArrayList<UiccCardInfo>(); } - return telephony.getUiccCardsInfo(); + return telephony.getUiccCardsInfo(mContext.getOpPackageName()); } catch (RemoteException e) { - return null; + Log.e(TAG, "Error in getUiccCardsInfo: " + e); + return new ArrayList<UiccCardInfo>(); } } @@ -8440,18 +8435,47 @@ public class TelephonyManager { } - /** @hide */ + /** + * Returns a well-formed IETF BCP 47 language tag representing the locale from the SIM, e.g, + * en-US. Returns {@code null} if no locale could be derived from subscriptions. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * + * @see Locale#toLanguageTag() + * @see Locale#forLanguageTag(String) + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @Nullable public String getSimLocale() { + try { + final ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getSimLocaleForSubscriber(getSubId()); + } + } catch (RemoteException ex) { + } + return null; + } + + /** + * TODO delete after SuW migrates to new API. + * @hide + */ public String getLocaleFromDefaultSim() { try { final ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getLocaleFromDefaultSim(); + return telephony.getSimLocaleForSubscriber(getSubId()); } } catch (RemoteException ex) { } return null; } + /** * Requests the modem activity info. The recipient will place the result * in `result`. @@ -8919,6 +8943,9 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) { + if (carriers == null || !SubscriptionManager.isValidPhoneId(slotIndex)) { + return -1; + } // Execute the method setCarrierRestrictionRules with an empty excluded list and // indicating priority for the allowed list. CarrierRestrictionRules carrierRestrictionRules = CarrierRestrictionRules.newBuilder() @@ -8929,7 +8956,7 @@ public class TelephonyManager { int result = setCarrierRestrictionRules(carrierRestrictionRules); - // Convert boolean result into int, as required by this method. + // Convert result into int, as required by this method. if (result == SET_CARRIER_RESTRICTION_SUCCESS) { return carriers.size(); } else { @@ -9022,9 +9049,11 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) { - CarrierRestrictionRules carrierRestrictionRule = getCarrierRestrictionRules(); - if (carrierRestrictionRule != null) { - return carrierRestrictionRule.getAllowedCarriers(); + if (SubscriptionManager.isValidPhoneId(slotIndex)) { + CarrierRestrictionRules carrierRestrictionRule = getCarrierRestrictionRules(); + if (carrierRestrictionRule != null) { + return carrierRestrictionRule.getAllowedCarriers(); + } } return new ArrayList<CarrierIdentifier>(0); } @@ -9941,4 +9970,120 @@ public class TelephonyManager { } return ret; } + + /** + * Indicate if the user is allowed to use multiple SIM cards at the same time to register + * on the network (e.g. Dual Standby or Dual Active) when the device supports it, or if the + * usage is restricted. This API is used to prevent usage of multiple SIM card, based on + * policies of the carrier. + * <p>Note: the API does not prevent access to the SIM cards for operations that don't require + * access to the network. + * + * @param isMultisimCarrierRestricted true if usage of multiple SIMs is restricted, false + * otherwise. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) { + try { + ITelephony service = getITelephony(); + if (service != null) { + service.setMultisimCarrierRestriction(isMultisimCarrierRestricted); + } + } catch (RemoteException e) { + Log.e(TAG, "setMultisimCarrierRestriction RemoteException", e); + } + } + + /** + * Returns if the usage of multiple SIM cards at the same time to register on the network + * (e.g. Dual Standby or Dual Active) is restricted. + * + * @return true if usage of multiple SIMs is restricted, false otherwise. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isMultisimCarrierRestricted() { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.isMultisimCarrierRestricted(); + } + } catch (RemoteException e) { + Log.e(TAG, "isMultisimCarrierRestricted RemoteException", e); + } + return true; + } + + /** + * Broadcast intent action for network country code changes. + * + * <p> + * The {@link #EXTRA_NETWORK_COUNTRY} extra indicates the country code of the current + * network returned by {@link #getNetworkCountryIso()}. + * + * @see #EXTRA_NETWORK_COUNTRY + * @see #getNetworkCountryIso() + */ + public static final String ACTION_NETWORK_COUNTRY_CHANGED = + "android.telephony.action.NETWORK_COUNTRY_CHANGED"; + + /** + * The extra used with an {@link #ACTION_NETWORK_COUNTRY_CHANGED} to specify the + * the country code in ISO 3166 format. + * <p class="note"> + * Retrieve with {@link android.content.Intent#getStringExtra(String)}. + */ + public static final String EXTRA_NETWORK_COUNTRY = + "android.telephony.extra.NETWORK_COUNTRY"; + /** + * Switch configs to enable multi-sim or switch back to single-sim + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * @param numOfSims number of live SIMs we want to switch to + * @throws android.os.RemoteException + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void switchMultiSimConfig(int numOfSims) { + //only proceed if multi-sim is not restricted + if (isMultisimCarrierRestricted()) { + Rlog.e(TAG, "switchMultiSimConfig not possible. It is restricted."); + return; + } + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.switchMultiSimConfig(numOfSims); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "switchMultiSimConfig RemoteException", ex); + } + } + + /** + * Get whether reboot is required or not after making changes to modem configurations. + * @Return {@code True} if reboot is required after making changes to modem configurations, + * otherwise return {@code False}. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isRebootRequiredForModemConfigChange() { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.isRebootRequiredForModemConfigChange(); + } + } catch (RemoteException e) { + Log.e(TAG, "isRebootRequiredForModemConfigChange RemoteException", e); + } + return false; + } } diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java index 45e4704e8894..19f357a14687 100644 --- a/telephony/java/android/telephony/UiccCardInfo.java +++ b/telephony/java/android/telephony/UiccCardInfo.java @@ -15,7 +15,6 @@ */ package android.telephony; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -23,10 +22,8 @@ import java.util.Objects; /** * The UiccCardInfo represents information about a currently inserted UICC or embedded eUICC. - * @hide */ -@SystemApi -public class UiccCardInfo implements Parcelable { +public final class UiccCardInfo implements Parcelable { private final boolean mIsEuicc; private final int mCardId; @@ -95,6 +92,9 @@ public class UiccCardInfo implements Parcelable { /** * Get the embedded ID (EID) of the eUICC. If the UiccCardInfo is not an eUICC * (see {@link #isEuicc()}), returns null. + * <p> + * Note that this field may be omitted if the caller does not have the correct permissions + * (see {@link TelephonyManager#getUiccCardsInfo()}). */ public String getEid() { if (!mIsEuicc) { @@ -105,6 +105,9 @@ public class UiccCardInfo implements Parcelable { /** * Get the ICCID of the UICC. + * <p> + * Note that this field may be omitted if the caller does not have the correct permissions + * (see {@link TelephonyManager#getUiccCardsInfo()}). */ public String getIccId() { return mIccId; @@ -117,6 +120,16 @@ public class UiccCardInfo implements Parcelable { return mSlotIndex; } + /** + * Returns a copy of the UiccCardinfo with the clears the EID and ICCID set to null. These + * values are generally private and require carrier privileges to view. + * + * @hide + */ + public UiccCardInfo getUnprivileged() { + return new UiccCardInfo(mIsEuicc, mCardId, null, null, mSlotIndex); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index 294c79ba57a2..3d2fe5fec14a 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -23,6 +23,7 @@ import android.annotation.SystemApi; import android.net.LinkAddress; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.data.ApnSetting.ProtocolType; import java.net.InetAddress; import java.util.ArrayList; @@ -40,7 +41,7 @@ public final class DataCallResponse implements Parcelable { private final int mSuggestedRetryTime; private final int mCid; private final int mActive; - private final String mType; + private final int mProtocolType; private final String mIfname; private final List<LinkAddress> mAddresses; private final List<InetAddress> mDnses; @@ -53,8 +54,8 @@ public final class DataCallResponse implements Parcelable { * @param suggestedRetryTime The suggested data retry time in milliseconds. * @param cid The unique id of the data connection. * @param active Data connection active status. 0 = inactive, 1 = dormant, 2 = active. - * @param type The connection protocol, should be one of the PDP_type values in TS 27.007 - * section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + * @param protocolType The connection protocol, should be one of the PDP_type values in 3GPP + * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". * @param ifname The network interface name. * @param addresses A list of addresses with optional "/" prefix length, e.g., * "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64". Typically 1 IPv4 or 1 IPv6 or @@ -71,7 +72,7 @@ public final class DataCallResponse implements Parcelable { * either not sent a value or sent an invalid value. */ public DataCallResponse(int status, int suggestedRetryTime, int cid, int active, - @Nullable String type, @Nullable String ifname, + @ProtocolType int protocolType, @Nullable String ifname, @Nullable List<LinkAddress> addresses, @Nullable List<InetAddress> dnses, @Nullable List<InetAddress> gateways, @@ -80,7 +81,7 @@ public final class DataCallResponse implements Parcelable { mSuggestedRetryTime = suggestedRetryTime; mCid = cid; mActive = active; - mType = (type == null) ? "" : type; + mProtocolType = protocolType; mIfname = (ifname == null) ? "" : ifname; mAddresses = (addresses == null) ? new ArrayList<>() : addresses; mDnses = (dnses == null) ? new ArrayList<>() : dnses; @@ -94,7 +95,7 @@ public final class DataCallResponse implements Parcelable { mSuggestedRetryTime = source.readInt(); mCid = source.readInt(); mActive = source.readInt(); - mType = source.readString(); + mProtocolType = source.readInt(); mIfname = source.readString(); mAddresses = new ArrayList<>(); source.readList(mAddresses, LinkAddress.class.getClassLoader()); @@ -128,11 +129,10 @@ public final class DataCallResponse implements Parcelable { public int getActive() { return mActive; } /** - * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section - * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + * @return The connection protocol type. */ - @NonNull - public String getType() { return mType; } + @ProtocolType + public int getProtocolType() { return mProtocolType; } /** * @return The network interface name. @@ -181,7 +181,7 @@ public final class DataCallResponse implements Parcelable { .append(" retry=").append(mSuggestedRetryTime) .append(" cid=").append(mCid) .append(" active=").append(mActive) - .append(" type=").append(mType) + .append(" protocolType=").append(mProtocolType) .append(" ifname=").append(mIfname) .append(" addresses=").append(mAddresses) .append(" dnses=").append(mDnses) @@ -205,7 +205,7 @@ public final class DataCallResponse implements Parcelable { && this.mSuggestedRetryTime == other.mSuggestedRetryTime && this.mCid == other.mCid && this.mActive == other.mActive - && this.mType.equals(other.mType) + && this.mProtocolType == other.mProtocolType && this.mIfname.equals(other.mIfname) && mAddresses.size() == other.mAddresses.size() && mAddresses.containsAll(other.mAddresses) @@ -220,8 +220,8 @@ public final class DataCallResponse implements Parcelable { @Override public int hashCode() { - return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mType, mIfname, mAddresses, - mDnses, mGateways, mPcscfs, mMtu); + return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mProtocolType, mIfname, + mAddresses, mDnses, mGateways, mPcscfs, mMtu); } @Override @@ -235,7 +235,7 @@ public final class DataCallResponse implements Parcelable { dest.writeInt(mSuggestedRetryTime); dest.writeInt(mCid); dest.writeInt(mActive); - dest.writeString(mType); + dest.writeInt(mProtocolType); dest.writeString(mIfname); dest.writeList(mAddresses); dest.writeList(mDnses); diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java index da4822cc1d14..1d196f9b2885 100644 --- a/telephony/java/android/telephony/data/DataProfile.java +++ b/telephony/java/android/telephony/data/DataProfile.java @@ -16,14 +16,23 @@ package android.telephony.data; +import static android.telephony.data.ApnSetting.ProtocolType; + +import android.annotation.IntDef; import android.annotation.SystemApi; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager.NetworkTypeBitMask; +import android.telephony.data.ApnSetting.ApnType; +import android.telephony.data.ApnSetting.AuthType; import android.text.TextUtils; import com.android.internal.telephony.RILConstants; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Description of a mobile data profile used for establishing * data connections. @@ -32,24 +41,39 @@ import com.android.internal.telephony.RILConstants; */ @SystemApi public final class DataProfile implements Parcelable { - - // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network. + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"TYPE_"}, + value = { + TYPE_COMMON, + TYPE_3GPP, + TYPE_3GPP2}) + public @interface DataProfileType {} + + /** Common data profile */ public static final int TYPE_COMMON = 0; + + /** 3GPP type data profile */ public static final int TYPE_3GPP = 1; + + /** 3GPP2 type data profile */ public static final int TYPE_3GPP2 = 2; private final int mProfileId; private final String mApn; - private final String mProtocol; + @ProtocolType + private final int mProtocolType; + @AuthType private final int mAuthType; private final String mUserName; private final String mPassword; + @DataProfileType private final int mType; private final int mMaxConnsTime; @@ -60,10 +84,13 @@ public final class DataProfile implements Parcelable { private final boolean mEnabled; + @ApnType private final int mSupportedApnTypesBitmap; - private final String mRoamingProtocol; + @ProtocolType + private final int mRoamingProtocolType; + @NetworkTypeBitMask private final int mBearerBitmap; private final int mMtu; @@ -73,14 +100,14 @@ public final class DataProfile implements Parcelable { private final boolean mPreferred; /** @hide */ - public DataProfile(int profileId, String apn, String protocol, int authType, String userName, - String password, int type, int maxConnsTime, int maxConns, int waitTime, - boolean enabled, int supportedApnTypesBitmap, String roamingProtocol, - int bearerBitmap, int mtu, boolean persistent, boolean preferred) { - + public DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType, + String userName, String password, int type, int maxConnsTime, int maxConns, + int waitTime, boolean enabled, @ApnType int supportedApnTypesBitmap, + @ProtocolType int roamingProtocolType, @NetworkTypeBitMask int bearerBitmap, + int mtu, boolean persistent, boolean preferred) { this.mProfileId = profileId; this.mApn = apn; - this.mProtocol = protocol; + this.mProtocolType = protocolType; if (authType == -1) { authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE : RILConstants.SETUP_DATA_AUTH_PAP_CHAP; @@ -95,7 +122,7 @@ public final class DataProfile implements Parcelable { this.mEnabled = enabled; this.mSupportedApnTypesBitmap = supportedApnTypesBitmap; - this.mRoamingProtocol = roamingProtocol; + this.mRoamingProtocolType = roamingProtocolType; this.mBearerBitmap = bearerBitmap; this.mMtu = mtu; this.mPersistent = persistent; @@ -106,7 +133,7 @@ public final class DataProfile implements Parcelable { public DataProfile(Parcel source) { mProfileId = source.readInt(); mApn = source.readString(); - mProtocol = source.readString(); + mProtocolType = source.readInt(); mAuthType = source.readInt(); mUserName = source.readString(); mPassword = source.readString(); @@ -116,7 +143,7 @@ public final class DataProfile implements Parcelable { mWaitTime = source.readInt(); mEnabled = source.readBoolean(); mSupportedApnTypesBitmap = source.readInt(); - mRoamingProtocol = source.readString(); + mRoamingProtocolType = source.readInt(); mBearerBitmap = source.readInt(); mMtu = source.readInt(); mPersistent = source.readBoolean(); @@ -134,16 +161,14 @@ public final class DataProfile implements Parcelable { public String getApn() { return mApn; } /** - * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section - * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1. */ - public String getProtocol() { return mProtocol; } + public @ProtocolType int getProtocol() { return mProtocolType; } /** - * @return The authentication protocol used for this PDP context - * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3) + * @return The authentication protocol used for this PDP context. */ - public int getAuthType() { return mAuthType; } + public @AuthType int getAuthType() { return mAuthType; } /** * @return The username for APN. Can be null. @@ -156,9 +181,9 @@ public final class DataProfile implements Parcelable { public String getPassword() { return mPassword; } /** - * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2. + * @return The profile type. */ - public int getType() { return mType; } + public @DataProfileType int getType() { return mType; } /** * @return The period in seconds to limit the maximum connections. @@ -183,20 +208,19 @@ public final class DataProfile implements Parcelable { public boolean isEnabled() { return mEnabled; } /** - * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit. + * @return The supported APN types bitmap. */ - public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; } + public @ApnType int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; } /** - * @return The connection protocol on roaming network, should be one of the PDP_type values in - * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP". + * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1. */ - public String getRoamingProtocol() { return mRoamingProtocol; } + public @ProtocolType int getRoamingProtocol() { return mRoamingProtocolType; } /** - * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit. + * @return The bearer bitmap indicating the applicable networks for this data profile. */ - public int getBearerBitmap() { return mBearerBitmap; } + public @NetworkTypeBitMask int getBearerBitmap() { return mBearerBitmap; } /** * @return The maximum transmission unit (MTU) size in bytes. @@ -222,12 +246,12 @@ public final class DataProfile implements Parcelable { @Override public String toString() { - return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType + return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType + "/" + (Build.IS_USER ? "***/***/***" : (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/" + mMaxConnsTime + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/" - + mRoamingProtocol + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/" + + mRoamingProtocolType + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/" + mPreferred; } @@ -242,7 +266,7 @@ public final class DataProfile implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mProfileId); dest.writeString(mApn); - dest.writeString(mProtocol); + dest.writeInt(mProtocolType); dest.writeInt(mAuthType); dest.writeString(mUserName); dest.writeString(mPassword); @@ -252,7 +276,7 @@ public final class DataProfile implements Parcelable { dest.writeInt(mWaitTime); dest.writeBoolean(mEnabled); dest.writeInt(mSupportedApnTypesBitmap); - dest.writeString(mRoamingProtocol); + dest.writeInt(mRoamingProtocolType); dest.writeInt(mBearerBitmap); dest.writeInt(mMtu); dest.writeBoolean(mPersistent); diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 74d1e838f186..79572b9706a9 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -157,7 +157,10 @@ public abstract class DataService extends Service { @Nullable LinkProperties linkProperties, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null); + if (callback != null) { + callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, + null); + } } /** @@ -176,7 +179,9 @@ public abstract class DataService extends Service { public void deactivateDataCall(int cid, @DeactivateDataReason int reason, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** @@ -190,7 +195,10 @@ public abstract class DataService extends Service { public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onSetInitialAttachApnComplete( + DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** @@ -206,7 +214,9 @@ public abstract class DataService extends Service { public void setDataProfile(List<DataProfile> dps, boolean isRoaming, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index a94b163ffd75..e68256d086bc 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -27,6 +27,7 @@ import android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -176,6 +177,12 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * Bit-field which indicates the number is from the platform-maintained database. */ public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 1 << 4; + /** + * Bit-field which indicates the number is from test mode. + * + * @hide + */ + public static final int EMERGENCY_NUMBER_SOURCE_TEST = 1 << 5; /** Bit-field which indicates the number is from the modem config. */ public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = EmergencyNumberSource.MODEM_CONFIG; @@ -232,18 +239,21 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu private final String mCountryIso; private final String mMnc; private final int mEmergencyServiceCategoryBitmask; + private final List<String> mEmergencyUrns; private final int mEmergencyNumberSourceBitmask; private final int mEmergencyCallRouting; /** @hide */ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc, @EmergencyServiceCategories int emergencyServiceCategories, + @NonNull List<String> emergencyUrns, @EmergencyNumberSources int emergencyNumberSources, @EmergencyCallRouting int emergencyCallRouting) { this.mNumber = number; this.mCountryIso = countryIso; this.mMnc = mnc; this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories; + this.mEmergencyUrns = emergencyUrns; this.mEmergencyNumberSourceBitmask = emergencyNumberSources; this.mEmergencyCallRouting = emergencyCallRouting; } @@ -254,6 +264,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu mCountryIso = source.readString(); mMnc = source.readString(); mEmergencyServiceCategoryBitmask = source.readInt(); + mEmergencyUrns = source.createStringArrayList(); mEmergencyNumberSourceBitmask = source.readInt(); mEmergencyCallRouting = source.readInt(); } @@ -265,6 +276,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu dest.writeString(mCountryIso); dest.writeString(mMnc); dest.writeInt(mEmergencyServiceCategoryBitmask); + dest.writeStringList(mEmergencyUrns); dest.writeInt(mEmergencyNumberSourceBitmask); dest.writeInt(mEmergencyCallRouting); } @@ -322,6 +334,21 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } /** + * Returns the bitmask of emergency service categories of the emergency number for + * internal dialing. + * + * @return bitmask of the emergency service categories + * + * @hide + */ + public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() { + if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) { + return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; + } + return mEmergencyServiceCategoryBitmask; + } + + /** * Returns the emergency service categories of the emergency number. * * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only @@ -345,6 +372,22 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } /** + * Returns the list of emergency Uniform Resources Names (URN) of the emergency number. + * + * For example, {@code urn:service:sos} is the generic URN for contacting emergency services + * of all type. + * + * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General; + * RFC 5031 + * + * @return list of emergency Uniform Resources Names (URN) or an empty list if the emergency + * number does not have a specified emergency Uniform Resource Name. + */ + public @NonNull List<String> getEmergencyUrns() { + return mEmergencyUrns; + } + + /** * Checks if the emergency service category is unspecified for the emergency number * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}. * @@ -434,6 +477,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso + "|Mnc-" + mMnc + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask) + + "|Urns-" + mEmergencyUrns + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask) + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting); } @@ -448,6 +492,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu && mCountryIso.equals(other.mCountryIso) && mMnc.equals(other.mMnc) && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask + && mEmergencyUrns.equals(other.mEmergencyUrns) && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask && mEmergencyCallRouting == other.mEmergencyCallRouting; } @@ -455,7 +500,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu @Override public int hashCode() { return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask, - mEmergencyNumberSourceBitmask, mEmergencyCallRouting); + mEmergencyUrns, mEmergencyNumberSourceBitmask, mEmergencyCallRouting); } /** @@ -554,6 +599,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu emergencyNumberList.remove(i--); } } + Collections.sort(emergencyNumberList); } /** @@ -584,9 +630,18 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu != second.getEmergencyServiceCategoryBitmask()) { return false; } + if (first.getEmergencyUrns().equals(second.getEmergencyUrns())) { + return false; + } if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) { return false; } + // Never merge two numbers if one of them is from test mode but the other one is not; + // This supports to remove a number from the test mode. + if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST) + ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) { + return false; + } return true; } @@ -605,10 +660,20 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu if (areSameEmergencyNumbers(first, second)) { return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), first.getEmergencyServiceCategoryBitmask(), + first.getEmergencyUrns(), first.getEmergencyNumberSourceBitmask() | second.getEmergencyNumberSourceBitmask(), first.getEmergencyCallRouting()); } return null; } + + /** + * Validate Emergency Number address that only allows '0'-'9', '*', or '#' + * + * @hide + */ + public static boolean validateEmergencyNumberAddress(String address) { + return address.matches("[0-9*#]+"); + } } diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 9c8d078a579b..59167b7d5bba 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -33,6 +33,8 @@ import com.android.internal.telephony.PhoneConstants; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** * Parcelable object to handle IMS call profile. @@ -323,6 +325,15 @@ public final class ImsCallProfile implements Parcelable { EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; /** + * The emergency Uniform Resource Names (URN), only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY}. + * + * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General; + * 3gpp 22.101, Section 10 - Emergency Calls. + */ + private List<String> mEmergencyUrns = new ArrayList<>(); + + /** * The emergency call routing, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -336,6 +347,9 @@ public final class ImsCallProfile implements Parcelable { private @EmergencyCallRouting int mEmergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + /** Indicates if the call is for testing purpose */ + private boolean mEmergencyCallTesting = false; + /** * Extras associated with this {@link ImsCallProfile}. * <p> @@ -523,8 +537,10 @@ public final class ImsCallProfile implements Parcelable { + ", callType=" + mCallType + ", restrictCause=" + mRestrictCause + ", mediaProfile=" + mMediaProfile.toString() - + ", emergencyServiceCategories=" + mEmergencyCallRouting - + ", emergencyCallRouting=" + mEmergencyCallRouting + " }"; + + ", emergencyServiceCategories=" + mEmergencyServiceCategories + + ", emergencyUrns=" + mEmergencyUrns + + ", emergencyCallRouting=" + mEmergencyCallRouting + + ", emergencyCallTesting=" + mEmergencyCallTesting + " }"; } @Override @@ -540,7 +556,9 @@ public final class ImsCallProfile implements Parcelable { out.writeBundle(filteredExtras); out.writeParcelable(mMediaProfile, 0); out.writeInt(mEmergencyServiceCategories); + out.writeStringList(mEmergencyUrns); out.writeInt(mEmergencyCallRouting); + out.writeBoolean(mEmergencyCallTesting); } private void readFromParcel(Parcel in) { @@ -549,7 +567,9 @@ public final class ImsCallProfile implements Parcelable { mCallExtras = in.readBundle(); mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader()); mEmergencyServiceCategories = in.readInt(); + mEmergencyUrns = in.createStringArrayList(); mEmergencyCallRouting = in.readInt(); + mEmergencyCallTesting = in.readBoolean(); } public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() { @@ -760,20 +780,23 @@ public final class ImsCallProfile implements Parcelable { } /** - * Set the emergency service categories and emergency call routing. The set value is valid + * Set the emergency number information. The set value is valid * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY} * * Reference: 3gpp 23.167, Section 6 - Functional description; + * 3gpp 24.503, Section 5.1.6.8.1 - General; * 3gpp 22.101, Section 10 - Emergency Calls. * * @hide */ public void setEmergencyCallInfo(EmergencyNumber num) { - setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask()); + setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial()); + setEmergencyUrns(num.getEmergencyUrns()); setEmergencyCallRouting(num.getEmergencyCallRouting()); + setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask() + == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } - /** * Set the emergency service categories. The set value is valid only if * {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY} @@ -800,6 +823,18 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType} + * returns {@link #SERVICE_TYPE_EMERGENCY}. + * + * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General; + * 3gpp 22.101, Section 10 - Emergency Calls. + */ + @VisibleForTesting + public void setEmergencyUrns(List<String> emergencyUrns) { + mEmergencyUrns = emergencyUrns; + } + + /** * Set the emergency call routing, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -816,6 +851,15 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set if this is for testing emergency call, only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY}. + */ + @VisibleForTesting + public void setEmergencyCallTesting(boolean isTesting) { + mEmergencyCallTesting = isTesting; + } + + /** * Get the emergency service categories, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -841,6 +885,17 @@ public final class ImsCallProfile implements Parcelable { } /** + * Get the emergency Uniform Resource Names (URN), only valid if {@link #getServiceType} + * returns {@link #SERVICE_TYPE_EMERGENCY}. + * + * Reference: 3gpp 24.503, Section 5.1.6.8.1 - General; + * 3gpp 22.101, Section 10 - Emergency Calls. + */ + public List<String> getEmergencyUrns() { + return mEmergencyUrns; + } + + /** * Get the emergency call routing, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -854,4 +909,11 @@ public final class ImsCallProfile implements Parcelable { public @EmergencyCallRouting int getEmergencyCallRouting() { return mEmergencyCallRouting; } + + /** + * Get if the emergency call is for testing purpose. + */ + public boolean isEmergencyCallTesting() { + return mEmergencyCallTesting; + } } diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java index 3921cfbbfce7..7250eee70ecb 100644 --- a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java +++ b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java @@ -64,6 +64,10 @@ public class StatusCode implements Parcelable { public static final int UCE_NO_CHANGE_IN_CAP = 13; /** Service is unknown. */ public static final int UCE_SERVICE_UNKNOWN = 14; + /** Service cannot support Invalid Feature Tag */ + public static final int UCE_INVALID_FEATURE_TAG = 15; + /** Service is Available */ + public static final int UCE_SERVICE_AVAILABLE = 16; private int mStatusCode = UCE_SUCCESS; diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl index 43f83cd94d57..1fb8513d410a 100644 --- a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl +++ b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl @@ -66,10 +66,30 @@ interface IUceService * service the client created. * * @return optionsServiceHandle + * * @hide + * + * @deprecated This is replaced with new API createOptionsServiceForSubscription() */ int createOptionsService(IOptionsListener optionsListener, inout UceLong optionsServiceListenerHdl); + /** + * Creates a options service for Capability Discovery. + * @param optionsListener IOptionsListener object. + * @param optionsServiceListenerHdl wrapper for client's listener handle to be stored. + * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested + * + * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and + * used to validate callbacks received in IPresenceListener are indeed from the + * service the client created. + * + * @return optionsServiceHandle + * + * @hide + */ + int createOptionsServiceForSubscription(IOptionsListener optionsListener, + inout UceLong optionsServiceListenerHdl, + in String iccId); /** * Destroys a Options service. @@ -89,14 +109,36 @@ interface IUceService * service the client created. * * @return presenceServiceHdl + * * @hide + * + * @deprecated This is replaced with new API createPresenceServiceForSubscription() */ int createPresenceService(IPresenceListener presenceServiceListener, inout UceLong presenceServiceListenerHdl); + /** + * Creates a presence service. + * @param presenceServiceListener IPresenceListener object + * @param presenceServiceListenerHdl wrapper for client's listener handle to be stored. + * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested + * + * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and + * used to validate callbacks received in IPresenceListener are indeed from the + * service the client created. + * + * @return presenceServiceHdl + * + * @hide + */ + int createPresenceServiceForSubscription(IPresenceListener presenceServiceListener, + inout UceLong presenceServiceListenerHdl, + in String iccId); /** * Destroys a presence service. + * * @param presenceServiceHdl handle returned during createPresenceService() + * * @hide */ void destroyPresenceService(int presenceServiceHdl); @@ -105,23 +147,55 @@ interface IUceService /** * Query the UCE Service for information to know whether the is registered. + * * @return boolean, true if Registered to for network events else false. + * * @hide */ boolean getServiceStatus(); /** * Query the UCE Service for presence Service. + * * @return IPresenceService object. + * * @hide + * + * @deprecated use API getPresenceServiceForSubscription() */ IPresenceService getPresenceService(); /** + * Query the UCE Service for presence Service. + * + * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested + * + * @return IPresenceService object. + * + * @hide + */ + IPresenceService getPresenceServiceForSubscription(in String iccId); + + /** * Query the UCE Service for options service object. + * * @return IOptionsService object. + * + * @deprecated use API getOptionsServiceForSubscription() + * * @hide */ IOptionsService getOptionsService(); + /** + * Query the UCE Service for options service object. + * + * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested + * + * @return IOptionsService object. + * + * @hide + */ + IOptionsService getOptionsServiceForSubscription(in String iccId); + } diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java index 3660e039582d..ceb191910427 100644 --- a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java +++ b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java @@ -56,6 +56,14 @@ public abstract class UceServiceBase { return onCreateOptionsService(optionsListener, optionsServiceListenerHdl); } + @Override + public int createOptionsServiceForSubscription(IOptionsListener optionsListener, + UceLong optionsServiceListenerHdl, + String iccId) { + return onCreateOptionsService(optionsListener, optionsServiceListenerHdl, + iccId); + } + @Override public void destroyOptionsService(int optionsServiceHandle) { @@ -70,6 +78,14 @@ public abstract class UceServiceBase { } @Override + public int createPresenceServiceForSubscription(IPresenceListener presServiceListener, + UceLong presServiceListenerHdl, + String iccId) { + return onCreatePresService(presServiceListener, presServiceListenerHdl, + iccId); + } + + @Override public void destroyPresenceService(int presServiceHdl) { onDestroyPresService(presServiceHdl); } @@ -85,9 +101,19 @@ public abstract class UceServiceBase { } @Override + public IPresenceService getPresenceServiceForSubscription(String iccId) { + return onGetPresenceService(iccId); + } + + @Override public IOptionsService getOptionsService() { return onGetOptionsService(); } + + @Override + public IOptionsService getOptionsServiceForSubscription(String iccId) { + return onGetOptionsService(iccId); + } } private UceServiceBinder mBinder; @@ -120,6 +146,13 @@ public abstract class UceServiceBase { return 0; } + protected int onCreateOptionsService(IOptionsListener optionsListener, + UceLong optionsServiceListenerHdl, + String iccId) { + //no-op + return 0; + } + protected void onDestroyOptionsService(int cdServiceHandle) { //no-op return; @@ -131,6 +164,13 @@ public abstract class UceServiceBase { return 0; } + protected int onCreatePresService(IPresenceListener presServiceListener, + UceLong presServiceListenerHdl, + String iccId) { + //no-op + return 0; + } + protected void onDestroyPresService(int presServiceHdl) { //no-op return; @@ -146,8 +186,18 @@ public abstract class UceServiceBase { return null; } + protected IPresenceService onGetPresenceService(String iccId) { + //no-op + return null; + } + protected IOptionsService onGetOptionsService () { //no-op return null; } + + protected IOptionsService onGetOptionsService (String iccId) { + //no-op + return null; + } } diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 3dbebe832fac..322ce45797ec 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -27,6 +27,7 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsReasonInfo; oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); @@ -58,5 +59,6 @@ oneway interface IPhoneStateListener { void onCallAttributesChanged(in CallAttributes callAttributes); void onEmergencyNumberListChanged(in Map emergencyNumberList); void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause); + void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 26fcf8344921..c7061dfe25f1 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -42,6 +42,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; +import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; @@ -1177,12 +1178,12 @@ interface ITelephony { void factoryReset(int subId); /** - * An estimate of the users's current locale based on the default SIM. + * Returns users's current locale based on the SIM. * * The returned string will be a well formed BCP-47 language tag, or {@code null} * if no locale could be derived. */ - String getLocaleFromDefaultSim(); + String getSimLocaleForSubscriber(int subId); /** * Requests the modem activity info asynchronously. @@ -1483,25 +1484,34 @@ interface ITelephony { * Get the card ID of the default eUICC card. If there is no eUICC, returns * {@link #INVALID_CARD_ID}. * - * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} - * * @param subId subscription ID used for authentication * @param callingPackage package making the call * @return card ID of the default eUICC card. - * @hide */ - int getCardIdForDefaultEuicc(int subId, String callingPackage); + int getCardIdForDefaultEuicc(int subId, String callingPackage); /** - * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more - * details on the kind of information available. + * Gets information about currently inserted UICCs and enabled eUICCs. + * <p> + * Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * <p> + * If the caller has carrier priviliges on any active subscription, then they have permission to + * get simple information like the card ID ({@link UiccCardInfo#getCardId()}), whether the card + * is an eUICC ({@link UiccCardInfo#isEuicc()}), and the slot index where the card is inserted + * ({@link UiccCardInfo#getSlotIndex()}). + * <p> + * To get private information such as the EID ({@link UiccCardInfo#getEid()}) or ICCID + * ({@link UiccCardInfo#getIccId()}), the caller must have carrier priviliges on that specific + * UICC or eUICC card. + * <p> + * See {@link UiccCardInfo} for more details on the kind of information available. * - * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the - * currently inserted UICCs and eUICCs. - * - * @hide + * @param callingPackage package making the call, used to evaluate carrier privileges + * @return a list of UiccCardInfo objects, representing information on the currently inserted + * UICCs and eUICCs. Each UiccCardInfo in the list will have private information filtered out if + * the caller does not have adequate permissions for that card. */ - UiccCardInfo[] getUiccCardsInfo(); + List<UiccCardInfo> getUiccCardsInfo(String callingPackage); /** * Get slot info for all the UICC slots. @@ -1794,7 +1804,44 @@ interface ITelephony { int setImsProvisioningString(int subId, int key, String value); /** + * Update Emergency Number List for Test Mode. + */ + void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num); + + /** + * Get the full emergency number list for Test Mode. + */ + List<String> getEmergencyNumberListTestMode(); + + /** * Enable or disable a logical modem stack associated with the slotIndex. */ boolean enableModemForSlot(int slotIndex, boolean enable); + + /** + * Indicate if the enablement of multi SIM functionality is restricted. + * @hide + */ + void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted); + + /** + * Returns if the usage of multiple SIM cards at the same time is restricted. + * @hide + */ + boolean isMultisimCarrierRestricted(); + + /** + * Switch configs to enable multi-sim or switch back to single-sim + * @hide + */ + void switchMultiSimConfig(int numOfSims); + /** + * Get how many modems have been activated on the phone + * @hide + */ + int getNumOfActiveSims(); + /** + * Get if reboot is required upon altering modems configurations + */ + boolean isRebootRequiredForModemConfigChange(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 2be1f419db4d..e9eba324acb0 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -22,6 +22,7 @@ import android.net.NetworkCapabilities; import android.os.Bundle; import android.telephony.CallQuality; import android.telephony.CellInfo; +import android.telephony.ims.ImsReasonInfo; import android.telephony.PhoneCapability; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; @@ -84,4 +85,5 @@ interface ITelephonyRegistry { void notifyRadioPowerStateChanged(in int state); void notifyEmergencyNumberList(); void notifyCallQualityChanged(in CallQuality callQuality, int phoneId); + void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo); } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 599503c40ab0..08e30dedca74 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -192,31 +192,11 @@ public interface RILConstants { int LTE_ON_CDMA_FALSE = 0; int LTE_ON_CDMA_TRUE = 1; - int CDM_TTY_MODE_DISABLED = 0; - int CDM_TTY_MODE_ENABLED = 1; - - int CDM_TTY_FULL_MODE = 1; - int CDM_TTY_HCO_MODE = 2; - int CDM_TTY_VCO_MODE = 3; - - /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */ - int SETUP_DATA_TECH_CDMA = 0; - int SETUP_DATA_TECH_GSM = 1; - int SETUP_DATA_AUTH_NONE = 0; int SETUP_DATA_AUTH_PAP = 1; int SETUP_DATA_AUTH_CHAP = 2; int SETUP_DATA_AUTH_PAP_CHAP = 3; - String SETUP_DATA_PROTOCOL_IP = "IP"; - String SETUP_DATA_PROTOCOL_IPV6 = "IPV6"; - String SETUP_DATA_PROTOCOL_IPV4V6 = "IPV4V6"; - - /* NV config radio reset types. */ - int NV_CONFIG_RELOAD_RESET = 1; - int NV_CONFIG_ERASE_RESET = 2; - int NV_CONFIG_FACTORY_RESET = 3; - /* LCE service related constants. */ int LCE_NOT_AVAILABLE = -1; int LCE_STOPPED = 0; @@ -424,6 +404,7 @@ public interface RILConstants { int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204; int RIL_REQUEST_EMERGENCY_DIAL = 205; int RIL_REQUEST_GET_PHONE_CAPABILITY = 206; + int RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG = 207; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 6567ea764b50..603c4c2870d7 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -194,6 +194,13 @@ public interface TelephonyProperties */ static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config"; + /** + * Property to indicate if reboot is required when changing modems configurations + * Type: String(true, false) default is false; most devices don't need reboot + */ + String PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE = + "persist.radio.reboot_on_modem_change"; + /** * Property to store default subscription. */ diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java index 7641d0095a70..0433f9234b47 100644 --- a/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java +++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java @@ -70,6 +70,7 @@ public class RunLocalBenchmarksActivity extends AppCompatActivity { R.id.benchmark_text_low_hitrate, R.id.benchmark_edit_text_input, R.id.benchmark_overdraw, + R.id.benchmark_bitmap_upload, }; public static class LocalBenchmarksList extends ListFragment { @@ -204,6 +205,7 @@ public class RunLocalBenchmarksActivity extends AppCompatActivity { case R.id.benchmark_text_low_hitrate: case R.id.benchmark_edit_text_input: case R.id.benchmark_overdraw: + case R.id.benchmark_bitmap_upload: case R.id.benchmark_memory_bandwidth: case R.id.benchmark_memory_latency: case R.id.benchmark_power_management: @@ -323,6 +325,9 @@ public class RunLocalBenchmarksActivity extends AppCompatActivity { intent = new Intent(getApplicationContext(), EditTextInputActivity.class); break; case R.id.benchmark_overdraw: + intent = new Intent(getApplicationContext(), FullScreenOverdrawActivity.class); + break; + case R.id.benchmark_bitmap_upload: intent = new Intent(getApplicationContext(), BitmapUploadActivity.class); break; case R.id.benchmark_memory_bandwidth: diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/registry/BenchmarkRegistry.java b/tests/JankBench/app/src/main/java/com/android/benchmark/registry/BenchmarkRegistry.java index 89c6aedd8b5c..5723c599d91a 100644 --- a/tests/JankBench/app/src/main/java/com/android/benchmark/registry/BenchmarkRegistry.java +++ b/tests/JankBench/app/src/main/java/com/android/benchmark/registry/BenchmarkRegistry.java @@ -229,6 +229,8 @@ public class BenchmarkRegistry { return context.getString(R.string.cpu_gflops_name); case R.id.benchmark_overdraw: return context.getString(R.string.overdraw_name); + case R.id.benchmark_bitmap_upload: + return context.getString(R.string.bitmap_upload_name); default: return "Some Benchmark"; } diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/ui/BitmapUploadActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/ui/BitmapUploadActivity.java index f6a528a8a966..1c96cace1606 100644 --- a/tests/JankBench/app/src/main/java/com/android/benchmark/ui/BitmapUploadActivity.java +++ b/tests/JankBench/app/src/main/java/com/android/benchmark/ui/BitmapUploadActivity.java @@ -32,6 +32,7 @@ import android.view.MotionEvent; import android.view.View; import com.android.benchmark.R; +import com.android.benchmark.registry.BenchmarkRegistry; import com.android.benchmark.ui.automation.Automator; import com.android.benchmark.ui.automation.Interaction; @@ -124,7 +125,9 @@ public class BitmapUploadActivity extends AppCompatActivity { final int runId = getIntent().getIntExtra("com.android.benchmark.RUN_ID", 0); final int iteration = getIntent().getIntExtra("com.android.benchmark.ITERATION", -1); - mAutomator = new Automator("BMUpload", runId, iteration, getWindow(), + String name = BenchmarkRegistry.getBenchmarkName(this, R.id.benchmark_bitmap_upload); + + mAutomator = new Automator(name, runId, iteration, getWindow(), new Automator.AutomateCallback() { @Override public void onPostAutomate() { diff --git a/tests/JankBench/app/src/main/res/values/ids.xml b/tests/JankBench/app/src/main/res/values/ids.xml index 6801fd9f61ec..694e0d9a6917 100644 --- a/tests/JankBench/app/src/main/res/values/ids.xml +++ b/tests/JankBench/app/src/main/res/values/ids.xml @@ -23,6 +23,7 @@ <item name="benchmark_text_low_hitrate" type="id" /> <item name="benchmark_edit_text_input" type="id" /> <item name="benchmark_overdraw" type="id" /> + <item name="benchmark_bitmap_upload" type="id" /> <item name="benchmark_memory_bandwidth" type="id" /> <item name="benchmark_memory_latency" type="id" /> <item name="benchmark_power_management" type="id" /> diff --git a/tests/JankBench/app/src/main/res/values/strings.xml b/tests/JankBench/app/src/main/res/values/strings.xml index 270adf89e4ed..5c2405899db9 100644 --- a/tests/JankBench/app/src/main/res/values/strings.xml +++ b/tests/JankBench/app/src/main/res/values/strings.xml @@ -33,6 +33,8 @@ <string name="edit_text_input_description">Tests edit text input</string> <string name="overdraw_name">Overdraw Test</string> <string name="overdraw_description">Tests how the device handles overdraw</string> + <string name="bitmap_upload_name">Bitmap Upload Test</string> + <string name="bitmap_upload_description">Tests bitmap upload</string> <string name="memory_bandwidth_name">Memory Bandwidth</string> <string name="memory_bandwidth_description">Test device\'s memory bandwidth</string> <string name="memory_latency_name">Memory Latency</string> diff --git a/tests/JankBench/app/src/main/res/xml/benchmark.xml b/tests/JankBench/app/src/main/res/xml/benchmark.xml index 07c453c25359..fccc7b9d3776 100644 --- a/tests/JankBench/app/src/main/res/xml/benchmark.xml +++ b/tests/JankBench/app/src/main/res/xml/benchmark.xml @@ -62,6 +62,12 @@ benchmark:category="ui" benchmark:description="@string/overdraw_description" /> + <com.android.benchmark.Benchmark + benchmark:name="@string/bitmap_upload_name" + benchmark:id="@id/benchmark_bitmap_upload" + benchmark:category="ui" + benchmark:description="@string/bitmap_upload_description" /> + <!-- <com.android.benchmark.Benchmark benchmark:name="@string/memory_bandwidth_name" diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java index 3452819835f5..ba6e0f299057 100644 --- a/tests/net/java/android/net/NetworkUtilsTest.java +++ b/tests/net/java/android/net/NetworkUtilsTest.java @@ -16,161 +16,19 @@ package android.net; -import static android.net.NetworkUtils.getImplicitNetmask; -import static android.net.NetworkUtils.inet4AddressToIntHTH; -import static android.net.NetworkUtils.inet4AddressToIntHTL; -import static android.net.NetworkUtils.intToInet4AddressHTH; -import static android.net.NetworkUtils.intToInet4AddressHTL; -import static android.net.NetworkUtils.netmaskToPrefixLength; -import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; -import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL; -import static android.net.NetworkUtils.getBroadcastAddress; -import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; - import static junit.framework.Assert.assertEquals; -import static org.junit.Assert.fail; - import android.support.test.runner.AndroidJUnit4; -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.TreeSet; - import org.junit.Test; import org.junit.runner.RunWith; +import java.math.BigInteger; +import java.util.TreeSet; + @RunWith(AndroidJUnit4.class) @android.support.test.filters.SmallTest public class NetworkUtilsTest { - - private InetAddress Address(String addr) { - return InetAddress.parseNumericAddress(addr); - } - - private Inet4Address IPv4Address(String addr) { - return (Inet4Address) Address(addr); - } - - @Test - public void testGetImplicitNetmask() { - assertEquals(8, getImplicitNetmask(IPv4Address("4.2.2.2"))); - assertEquals(8, getImplicitNetmask(IPv4Address("10.5.6.7"))); - assertEquals(16, getImplicitNetmask(IPv4Address("173.194.72.105"))); - assertEquals(16, getImplicitNetmask(IPv4Address("172.23.68.145"))); - assertEquals(24, getImplicitNetmask(IPv4Address("192.0.2.1"))); - assertEquals(24, getImplicitNetmask(IPv4Address("192.168.5.1"))); - assertEquals(32, getImplicitNetmask(IPv4Address("224.0.0.1"))); - assertEquals(32, getImplicitNetmask(IPv4Address("255.6.7.8"))); - } - - private void assertInvalidNetworkMask(Inet4Address addr) { - try { - netmaskToPrefixLength(addr); - fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testInet4AddressToIntHTL() { - assertEquals(0, inet4AddressToIntHTL(IPv4Address("0.0.0.0"))); - assertEquals(0x000080ff, inet4AddressToIntHTL(IPv4Address("255.128.0.0"))); - assertEquals(0x0080ff0a, inet4AddressToIntHTL(IPv4Address("10.255.128.0"))); - assertEquals(0x00feff0a, inet4AddressToIntHTL(IPv4Address("10.255.254.0"))); - assertEquals(0xfeffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.254"))); - assertEquals(0xffffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTL() { - assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTL(0)); - assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); - assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); - assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); - assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); - assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); - } - - @Test - public void testInet4AddressToIntHTH() { - assertEquals(0, inet4AddressToIntHTH(IPv4Address("0.0.0.0"))); - assertEquals(0xff800000, inet4AddressToIntHTH(IPv4Address("255.128.0.0"))); - assertEquals(0x0aff8000, inet4AddressToIntHTH(IPv4Address("10.255.128.0"))); - assertEquals(0x0afffe00, inet4AddressToIntHTH(IPv4Address("10.255.254.0"))); - assertEquals(0xc0a8fffe, inet4AddressToIntHTH(IPv4Address("192.168.255.254"))); - assertEquals(0xc0a8ffff, inet4AddressToIntHTH(IPv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTH() { - assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTH(0)); - assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); - assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); - assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); - assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); - assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); - } - - @Test - public void testNetmaskToPrefixLength() { - assertEquals(0, netmaskToPrefixLength(IPv4Address("0.0.0.0"))); - assertEquals(9, netmaskToPrefixLength(IPv4Address("255.128.0.0"))); - assertEquals(17, netmaskToPrefixLength(IPv4Address("255.255.128.0"))); - assertEquals(23, netmaskToPrefixLength(IPv4Address("255.255.254.0"))); - assertEquals(31, netmaskToPrefixLength(IPv4Address("255.255.255.254"))); - assertEquals(32, netmaskToPrefixLength(IPv4Address("255.255.255.255"))); - - assertInvalidNetworkMask(IPv4Address("0.0.0.1")); - assertInvalidNetworkMask(IPv4Address("255.255.255.253")); - assertInvalidNetworkMask(IPv4Address("255.255.0.255")); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTL() { - assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); - assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); - assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); - assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); - assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH() { - assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); - assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); - assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); - assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); - assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { - prefixLengthToV4NetmaskIntHTH(-1); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { - prefixLengthToV4NetmaskIntHTH(33); - } - - private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { - final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); - final int addrInt = inet4AddressToIntHTH(IPv4Address(addr)); - assertEquals(IPv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { - checkAddressMasking("192.168.0.0", "192.168.128.1", 16); - checkAddressMasking("255.240.0.0", "255.255.255.255", 12); - checkAddressMasking("255.255.255.255", "255.255.255.255", 32); - checkAddressMasking("0.0.0.0", "255.255.255.255", 0); - } - @Test public void testRoutedIPv4AddressCount() { final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator()); @@ -267,44 +125,4 @@ public class NetworkUtilsTest { assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536), NetworkUtils.routedIPv6AddressCount(set)); } - - @Test - public void testGetPrefixMaskAsAddress() { - assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); - assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); - assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); - assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_PrefixTooLarge() { - getPrefixMaskAsInet4Address(33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_NegativePrefix() { - getPrefixMaskAsInet4Address(-1); - } - - @Test - public void testGetBroadcastAddress() { - assertEquals("192.168.15.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress()); - assertEquals("192.255.255.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress()); - assertEquals("192.168.0.123", - getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress()); - assertEquals("255.255.255.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress()); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_PrefixTooLarge() { - getBroadcastAddress(IPv4Address("192.168.0.123"), 33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_NegativePrefix() { - getBroadcastAddress(IPv4Address("192.168.0.123"), -1); - } } diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java index 5bb573455358..2b5ad378e0ae 100644 --- a/tests/net/java/android/net/StaticIpConfigurationTest.java +++ b/tests/net/java/android/net/StaticIpConfigurationTest.java @@ -26,13 +26,13 @@ import android.os.Parcel; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.net.InetAddress; import java.util.HashSet; import java.util.Objects; -import org.junit.Test; -import org.junit.runner.RunWith; - @RunWith(AndroidJUnit4.class) @SmallTest public class StaticIpConfigurationTest { @@ -203,7 +203,7 @@ public class StaticIpConfigurationTest { try { s.writeToParcel(p, 0); p.setDataPosition(0); - s2 = StaticIpConfiguration.CREATOR.createFromParcel(p); + s2 = StaticIpConfiguration.readFromParcel(p); } finally { p.recycle(); } diff --git a/tests/net/java/android/net/ip/InterfaceControllerTest.java b/tests/net/java/android/net/ip/InterfaceControllerTest.java new file mode 100644 index 000000000000..d27a4f99cfd9 --- /dev/null +++ b/tests/net/java/android/net/ip/InterfaceControllerTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.ip; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.net.INetd; +import android.net.InetAddresses; +import android.net.InterfaceConfigurationParcel; +import android.net.LinkAddress; +import android.net.util.SharedLog; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class InterfaceControllerTest { + private static final String TEST_IFACE = "testif"; + private static final String TEST_IPV4_ADDR = "192.168.123.28"; + private static final int TEST_PREFIXLENGTH = 31; + + @Mock private INetd mNetd; + @Mock private SharedLog mLog; + @Captor private ArgumentCaptor<InterfaceConfigurationParcel> mConfigCaptor; + + private InterfaceController mController; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mController = new InterfaceController(TEST_IFACE, mNetd, mLog); + + doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture()); + } + + @Test + public void testSetIPv4Address() throws Exception { + mController.setIPv4Address( + new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR), + TEST_PREFIXLENGTH)); + verify(mNetd, times(1)).interfaceSetCfg(any()); + final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); + assertEquals(TEST_IFACE, parcel.ifName); + assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr); + assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength); + assertEquals("", parcel.hwAddr); + assertArrayEquals(new String[0], parcel.flags); + } + + @Test + public void testClearIPv4Address() throws Exception { + mController.clearIPv4Address(); + verify(mNetd, times(1)).interfaceSetCfg(any()); + final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); + assertEquals(TEST_IFACE, parcel.ifName); + assertEquals("0.0.0.0", parcel.ipv4Addr); + assertEquals(0, parcel.prefixLength); + assertEquals("", parcel.hwAddr); + assertArrayEquals(new String[0], parcel.flags); + } +} diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java index 80aac047a723..f7542a7b4bfa 100644 --- a/tests/net/java/android/net/ip/IpServerTest.java +++ b/tests/net/java/android/net/ip/IpServerTest.java @@ -22,11 +22,11 @@ import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; -import static android.net.NetworkUtils.intToInet4AddressHTH; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.ip.IpServer.STATE_AVAILABLE; import static android.net.ip.IpServer.STATE_TETHERED; import static android.net.ip.IpServer.STATE_UNAVAILABLE; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java new file mode 100644 index 000000000000..6da851400af1 --- /dev/null +++ b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.shared; + +import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; +import static android.net.shared.Inet4AddressUtils.getImplicitNetmask; +import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; +import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL; +import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength; +import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; +import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL; + +import static junit.framework.Assert.assertEquals; + +import static org.junit.Assert.fail; + +import android.net.InetAddresses; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class Inet4AddressUtilsTest { + + @Test + public void testInet4AddressToIntHTL() { + assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0"))); + assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0"))); + assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0"))); + assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0"))); + assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254"))); + assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTL() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); + } + + @Test + public void testInet4AddressToIntHTH() { + assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0"))); + assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0"))); + assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0"))); + assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0"))); + assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254"))); + assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255"))); + } + + @Test + public void testIntToInet4AddressHTH() { + assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0)); + assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); + assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); + assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); + assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); + assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); + } + + + @Test + public void testPrefixLengthToV4NetmaskIntHTL() { + assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); + assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); + assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); + assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); + assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH() { + assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); + assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); + assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); + assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); + assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); + assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { + prefixLengthToV4NetmaskIntHTH(-1); + } + + @Test(expected = IllegalArgumentException.class) + public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { + prefixLengthToV4NetmaskIntHTH(33); + } + + private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { + final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); + final int addrInt = inet4AddressToIntHTH(ipv4Address(addr)); + assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); + } + + @Test + public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { + checkAddressMasking("192.168.0.0", "192.168.128.1", 16); + checkAddressMasking("255.240.0.0", "255.255.255.255", 12); + checkAddressMasking("255.255.255.255", "255.255.255.255", 32); + checkAddressMasking("0.0.0.0", "255.255.255.255", 0); + } + + @Test + public void testGetImplicitNetmask() { + assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2"))); + assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7"))); + assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105"))); + assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1"))); + assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1"))); + assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8"))); + } + + private void assertInvalidNetworkMask(Inet4Address addr) { + try { + netmaskToPrefixLength(addr); + fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testNetmaskToPrefixLength() { + assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0"))); + assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0"))); + assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0"))); + assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0"))); + assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254"))); + assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255"))); + + assertInvalidNetworkMask(ipv4Address("0.0.0.1")); + assertInvalidNetworkMask(ipv4Address("255.255.255.253")); + assertInvalidNetworkMask(ipv4Address("255.255.0.255")); + } + + @Test + public void testGetPrefixMaskAsAddress() { + assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); + assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); + assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); + assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); + } + + @Test + public void testGetBroadcastAddress() { + assertEquals("192.168.15.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress()); + assertEquals("192.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress()); + assertEquals("192.168.0.123", + getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress()); + assertEquals("255.255.255.255", + getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_PrefixTooLarge() { + getBroadcastAddress(ipv4Address("192.168.0.123"), 33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBroadcastAddress_NegativePrefix() { + getBroadcastAddress(ipv4Address("192.168.0.123"), -1); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_PrefixTooLarge() { + getPrefixMaskAsInet4Address(33); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetPrefixMaskAsAddress_NegativePrefix() { + getPrefixMaskAsInet4Address(-1); + } + + private Inet4Address ipv4Address(String addr) { + return (Inet4Address) InetAddresses.parseNumericAddress(addr); + } +} diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java index 14df392cbe07..fb4d43c367db 100644 --- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java +++ b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java @@ -62,7 +62,7 @@ public class IpConfigurationParcelableUtilTest { mDhcpResults.leaseDuration = 3600; mDhcpResults.mtu = 1450; // Any added DhcpResults field must be included in equals() to be tested properly - assertFieldCountEquals(4, DhcpResults.class); + assertFieldCountEquals(8, DhcpResults.class); } @Test diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 923c7dd5fb94..ebfb69e1ad77 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -57,6 +57,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; 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.shared.NetworkParcelableUtil.fromStableParcelable; import static com.android.internal.util.TestUtils.waitForIdleHandler; import static com.android.internal.util.TestUtils.waitForIdleLooper; @@ -119,6 +120,7 @@ import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; +import android.net.NetworkParcelable; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; @@ -482,8 +484,8 @@ public class ConnectivityServiceTest { fail(e.getMessage()); } - final ArgumentCaptor<Network> nmNetworkCaptor = - ArgumentCaptor.forClass(Network.class); + final ArgumentCaptor<NetworkParcelable> nmNetworkCaptor = + ArgumentCaptor.forClass(NetworkParcelable.class); final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor = ArgumentCaptor.forClass(INetworkMonitorCallbacks.class); doNothing().when(mNetworkStack).makeNetworkMonitor( @@ -523,7 +525,8 @@ public class ConnectivityServiceTest { } }; - assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId); + assertEquals( + mNetworkAgent.netId, fromStableParcelable(nmNetworkCaptor.getValue()).netId); mNmCallbacks = nmCbCaptor.getValue(); try { @@ -903,6 +906,7 @@ public class ConnectivityServiceTest { mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mConnected = true; mConfig = new VpnConfig(); + mConfig.isMetered = false; } @Override diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 0b74d878f069..46de3d0608ff 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -168,6 +168,8 @@ public class VpnTest { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT; when(mContext.getApplicationInfo()).thenReturn(applicationInfo); + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(applicationInfo); doNothing().when(mNetService).registerObserver(any()); } @@ -246,17 +248,17 @@ public class VpnTest { assertFalse(vpn.getLockdown()); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertTrue(vpn.getLockdown()); // Remove always-on configuration. - assertTrue(vpn.setAlwaysOnPackage(null, false)); + assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList())); assertFalse(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); } @@ -270,11 +272,11 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -283,7 +285,7 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[1]); // Switch to another app. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -297,6 +299,87 @@ public class VpnTest { } @Test + public void testLockdownWhitelist() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + final UidRange user = UidRange.createForUser(primaryUser.id); + + // Set always-on with lockdown and whitelist app PKGS[2] from lockdown. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + + // Change whitelisted app to PKGS[3]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), + new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]); + assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]); + + // Change the VPN app. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[0] - 1), + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) + })); + assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); + + // Remove the whitelist. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null)); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), + new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.stop), + })); + assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], + user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0]); + + // Add the whitelist. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); + + // Try whitelisting a package with a comma, should be rejected. + assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d"))); + + // Pass a non-existent packages in the whitelist, they (and only they) should be ignored. + // Whitelisted package should change from PGKS[1] to PKGS[2]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, + Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{ + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + } + + @Test public void testLockdownAddingAProfile() throws Exception { final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); @@ -310,7 +393,7 @@ public class VpnTest { final UidRange profile = UidRange.createForUser(tempProfile.id); // Set lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[3] - 1), new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) @@ -436,7 +519,7 @@ public class VpnTest { .cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Start showing a notification for disconnected once always-on. - vpn.setAlwaysOnPackage(PKGS[0], false); + vpn.setAlwaysOnPackage(PKGS[0], false, null); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); @@ -450,7 +533,7 @@ public class VpnTest { .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Notification should be cleared after unsetting always-on package. - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); } @@ -463,23 +546,28 @@ public class VpnTest { final Network wifi = new Network(2); final Map<Network, NetworkCapabilities> networks = new HashMap<>(); - networks.put(mobile, new NetworkCapabilities() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_METERED) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .setLinkDownstreamBandwidthKbps(10)); - networks.put(wifi, new NetworkCapabilities() - .addTransportType(TRANSPORT_WIFI) - .addCapability(NET_CAPABILITY_INTERNET) - .addCapability(NET_CAPABILITY_NOT_ROAMING) - .addCapability(NET_CAPABILITY_NOT_CONGESTED) - .setLinkUpstreamBandwidthKbps(20)); + networks.put( + mobile, + new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .setLinkDownstreamBandwidthKbps(10)); + networks.put( + wifi, + new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_METERED) + .addCapability(NET_CAPABILITY_NOT_ROAMING) + .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .setLinkUpstreamBandwidthKbps(20)); setMockedNetworks(networks); final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -489,17 +577,33 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); + Vpn.updateCapabilities( + mConnectivityManager, + new Network[] {mobile}, + caps, + false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); assertEquals(10, caps.getLinkDownstreamBandwidthKbps()); assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps()); - assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */); + assertTrue(caps.hasTransport(TRANSPORT_VPN)); + assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); + assertTrue(caps.hasTransport(TRANSPORT_WIFI)); + assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps()); + assertEquals(20, caps.getLinkUpstreamBandwidthKbps()); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + Vpn.updateCapabilities( + mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -509,7 +613,11 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); + Vpn.updateCapabilities( + mConnectivityManager, + new Network[] {mobile, wifi}, + caps, + false /* isAlwaysMetered */); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -583,7 +691,9 @@ public class VpnTest { doAnswer(invocation -> { final String appName = (String) invocation.getArguments()[0]; final int userId = (int) invocation.getArguments()[1]; - return UserHandle.getUid(userId, packages.get(appName)); + Integer appId = packages.get(appName); + if (appId == null) throw new PackageManager.NameNotFoundException(appName); + return UserHandle.getUid(userId, appId); }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt()); } catch (Exception e) { } diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp index 5bc004d62ff2..cf85726105df 100644 --- a/tools/aapt2/link/ManifestFixer_test.cpp +++ b/tools/aapt2/link/ManifestFixer_test.cpp @@ -350,133 +350,133 @@ TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) { } TEST_F(ManifestFixerTest, DontUseDefaultVersionNameAndCode) { -ManifestFixerOptions options; -options.version_name_default = std::string("Beta"); -options.version_code_default = std::string("0x10000000"); + ManifestFixerOptions options; + options.version_name_default = std::string("Beta"); + options.version_code_default = std::string("0x10000000"); -std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" android:versionCode="0x20000000" android:versionName="Alpha" />)EOF", - options); -ASSERT_THAT(doc, NotNull()); + options); + ASSERT_THAT(doc, NotNull()); -xml::Element* manifest_el = doc->root.get(); -ASSERT_THAT(manifest_el, NotNull()); + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); -xml::Attribute* attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("Alpha")); + xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Alpha")); -attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("0x20000000")); + attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) { -ManifestFixerOptions options; -options.replace_version = true; -options.version_name_default = std::string("Beta"); -options.version_code_default = std::string("0x10000000"); + ManifestFixerOptions options; + options.replace_version = true; + options.version_name_default = std::string("Beta"); + options.version_code_default = std::string("0x10000000"); -std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" android:versionCode="0x20000000" android:versionName="Alpha" />)EOF", - options); -ASSERT_THAT(doc, NotNull()); + options); + ASSERT_THAT(doc, NotNull()); -xml::Element* manifest_el = doc->root.get(); -ASSERT_THAT(manifest_el, NotNull()); + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); -xml::Attribute* attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("Beta")); + xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Beta")); -attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("0x10000000")); + attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x10000000")); } TEST_F(ManifestFixerTest, ReplaceVersionName) { -ManifestFixerOptions options; -options.replace_version = true; -options.version_name_default = std::string("Beta"); + ManifestFixerOptions options; + options.replace_version = true; + options.version_name_default = std::string("Beta"); -std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" android:versionCode="0x20000000" android:versionName="Alpha" />)EOF", - options); -ASSERT_THAT(doc, NotNull()); + options); + ASSERT_THAT(doc, NotNull()); -xml::Element* manifest_el = doc->root.get(); -ASSERT_THAT(manifest_el, NotNull()); + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); -xml::Attribute* attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("Beta")); + xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Beta")); -attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("0x20000000")); + attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, ReplaceVersionCode) { -ManifestFixerOptions options; -options.replace_version = true; -options.version_code_default = std::string("0x10000000"); + ManifestFixerOptions options; + options.replace_version = true; + options.version_code_default = std::string("0x10000000"); -std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" android:versionCode="0x20000000" android:versionName="Alpha" />)EOF", - options); -ASSERT_THAT(doc, NotNull()); + options); + ASSERT_THAT(doc, NotNull()); -xml::Element* manifest_el = doc->root.get(); -ASSERT_THAT(manifest_el, NotNull()); + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); -xml::Attribute* attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("Alpha")); + xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Alpha")); -attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("0x10000000")); + attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x10000000")); } TEST_F(ManifestFixerTest, DontReplaceVersionNameOrCode) { -ManifestFixerOptions options; -options.replace_version = true; + ManifestFixerOptions options; + options.replace_version = true; -std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( + std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF( <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" android:versionCode="0x20000000" android:versionName="Alpha" />)EOF", - options); -ASSERT_THAT(doc, NotNull()); + options); + ASSERT_THAT(doc, NotNull()); -xml::Element* manifest_el = doc->root.get(); -ASSERT_THAT(manifest_el, NotNull()); + xml::Element* manifest_el = doc->root.get(); + ASSERT_THAT(manifest_el, NotNull()); -xml::Attribute* attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("Alpha")); + xml::Attribute* attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("Alpha")); -attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); -ASSERT_THAT(attr, NotNull()); -EXPECT_THAT(attr->value, StrEq("0x20000000")); + attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode"); + ASSERT_THAT(attr, NotNull()); + EXPECT_THAT(attr->value, StrEq("0x20000000")); } TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) { @@ -673,7 +673,8 @@ TEST_F(ManifestFixerTest, UnexpectedElementsInManifest) { options.warn_validation = true; // Unexpected element should result in a warning if the flag is set to 'true'. - std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options); + std::unique_ptr<xml::XmlResource> manifest = + VerifyWithOptions(input, options); ASSERT_THAT(manifest, NotNull()); // Unexpected element should result in an error if the flag is set to 'false'. diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 75c3eba7765b..59e89f515e82 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -223,6 +223,7 @@ class Package(): class V2Tokenizer(object): __slots__ = ["raw"] + SIGNATURE_PREFIX = "// Signature format: " DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.') STRING_SPECIAL = re.compile(r'["\\]') @@ -610,8 +611,12 @@ def _parse_stream_to_generator(f): else: blame = None - if line == 1 and raw == "// Signature format: 2.0": - sig_format = 2 + if line == 1 and raw.startswith("// Signature format: "): + sig_format_string = raw[len(V2Tokenizer.SIGNATURE_PREFIX):] + if sig_format_string in ["2.0", "3.0"]: + sig_format = 2 + else: + raise ValueError("Unknown format: %s" % (sig_format_string,)) elif raw.startswith("package"): pkg = Package(line, raw, blame) elif raw.startswith(" ") and raw.endswith("{"): diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py index 9c261d506dac..3716bf9f5d6f 100644 --- a/tools/apilint/apilint_test.py +++ b/tools/apilint/apilint_test.py @@ -164,6 +164,23 @@ package android { self.assertEquals(api['android.SomeEnum'].ctors[0].split[0], 'ctor') self.assertEquals(api['android.SomeEnum'].methods[0].split[0], 'method') +class ParseV3Stream(unittest.TestCase): + def test_field_kinds(self): + api = apilint._parse_stream(""" +// Signature format: 3.0 +package a { + + public final class ContextKt { + method public static inline <reified T> T! getSystemService(android.content.Context); + method public static inline void withStyledAttributes(android.content.Context, android.util.AttributeSet? set = null, int[] attrs, @AttrRes int defStyleAttr = 0, @StyleRes int defStyleRes = 0, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block); + } +} + """.strip().split('\n')) + self.assertEquals(api['a.ContextKt'].methods[0].name, 'getSystemService') + self.assertEquals(api['a.ContextKt'].methods[0].split[:4], ['method', 'public', 'static', 'inline']) + self.assertEquals(api['a.ContextKt'].methods[1].name, 'withStyledAttributes') + self.assertEquals(api['a.ContextKt'].methods[1].split[:4], ['method', 'public', 'static', 'inline']) + class V2TokenizerTests(unittest.TestCase): def _test(self, raw, expected): self.assertEquals(apilint.V2Tokenizer(raw).tokenize(), expected) |