Merge "API: Fix missing @NonNull annotations"
diff --git a/Android.bp b/Android.bp
index e39d1e7..0407c41 100644
--- a/Android.bp
+++ b/Android.bp
@@ -674,7 +674,7 @@
"ext",
],
- jarjar_rules: ":framework-hidl-jarjar",
+ jarjar_rules: "jarjar_rules_hidl.txt",
static_libs: [
"apex_aidl_interface-java",
@@ -684,18 +684,24 @@
"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 {
- name: "framework-hidl-jarjar",
- srcs: ["jarjar_rules_hidl.txt"],
-}
-
java_library {
name: "framework",
defaults: ["framework-defaults"],
@@ -759,19 +760,6 @@
}
// 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 @@
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 c128f81..db91b9d 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -6450,6 +6450,7 @@
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 @@
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 @@
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;
@@ -27850,6 +27853,7 @@
method public android.os.ParcelFileDescriptor establish();
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 setMtu(int);
method public android.net.VpnService.Builder setSession(String);
method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]);
@@ -29086,6 +29090,7 @@
}
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);
@@ -29098,6 +29103,7 @@
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...);
@@ -41953,8 +41959,8 @@
}
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();
@@ -42124,7 +42130,9 @@
field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+ field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+ field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
@@ -42212,6 +42220,9 @@
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";
@@ -42873,6 +42884,7 @@
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();
@@ -42989,6 +43001,7 @@
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();
@@ -43036,6 +43049,7 @@
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();
@@ -43127,6 +43141,7 @@
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
@@ -43194,6 +43209,18 @@
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);
@@ -43349,6 +43376,7 @@
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);
@@ -55504,13 +55532,13 @@
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;
}
@@ -55681,12 +55709,12 @@
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);
@@ -56175,8 +56203,8 @@
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);
@@ -56186,8 +56214,8 @@
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);
@@ -57013,45 +57041,45 @@
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();
@@ -57938,8 +57966,8 @@
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);
@@ -57951,7 +57979,7 @@
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);
@@ -57966,8 +57994,8 @@
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);
@@ -58168,7 +58196,7 @@
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();
@@ -58266,13 +58294,13 @@
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 {
@@ -58595,8 +58623,8 @@
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;
@@ -58604,10 +58632,10 @@
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>);
}
@@ -58642,20 +58670,20 @@
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();
@@ -58744,7 +58772,7 @@
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();
@@ -58787,8 +58815,8 @@
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();
@@ -58801,7 +58829,7 @@
}
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();
}
@@ -58809,9 +58837,9 @@
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;
}
@@ -58825,7 +58853,7 @@
}
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();
}
@@ -58837,8 +58865,8 @@
}
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();
}
}
@@ -59855,20 +59883,20 @@
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 {
@@ -59882,7 +59910,7 @@
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();
@@ -59896,8 +59924,8 @@
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();
@@ -59916,8 +59944,8 @@
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);
@@ -59931,8 +59959,8 @@
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 {
@@ -61765,20 +61793,20 @@
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);
}
@@ -64385,7 +64413,7 @@
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);
@@ -64625,7 +64653,7 @@
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);
@@ -66279,8 +66307,8 @@
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> {
@@ -66389,161 +66417,161 @@
}
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 {
@@ -66627,7 +66655,7 @@
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);
@@ -66715,8 +66743,8 @@
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;
}
@@ -66727,7 +66755,7 @@
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);
@@ -66757,12 +66785,12 @@
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>);
@@ -67280,7 +67308,7 @@
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);
@@ -67298,8 +67326,8 @@
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();
@@ -67493,7 +67521,7 @@
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);
@@ -68158,7 +68186,7 @@
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);
@@ -68178,7 +68206,7 @@
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> {
@@ -68569,7 +68597,7 @@
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>);
@@ -68597,8 +68625,8 @@
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 {
@@ -70350,7 +70378,7 @@
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);
@@ -70363,7 +70391,7 @@
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);
@@ -70379,7 +70407,7 @@
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);
@@ -70390,8 +70418,8 @@
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;
@@ -70653,8 +70681,8 @@
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 8ce317f..097cb70 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -743,14 +743,18 @@
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean getSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
field public static final int ACCESS_ALLOWED = 1; // 0x1
field public static final int ACCESS_REJECTED = 2; // 0x2
field public static final int ACCESS_UNKNOWN = 0; // 0x0
+ field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+ field public static final String EXTRA_SILENCE_ENABLED = "android.bluetooth.device.extra.SILENCE_ENABLED";
field public static final int METADATA_COMPANION_APP = 4; // 0x4
field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
@@ -835,6 +839,7 @@
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";
@@ -3083,12 +3088,14 @@
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();
@@ -3099,6 +3106,7 @@
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();
@@ -3113,6 +3121,7 @@
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);
@@ -3129,6 +3138,7 @@
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -3214,10 +3224,31 @@
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 {
@@ -3239,6 +3270,49 @@
}
+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 {
@@ -3398,10 +3472,19 @@
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;
}
}
@@ -3861,6 +3944,7 @@
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
}
@@ -3877,6 +3961,36 @@
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";
@@ -5933,7 +6047,7 @@
}
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 onPreciseCallStateChanged(android.telephony.PreciseCallState);
method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
@@ -6112,7 +6226,6 @@
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();
}
@@ -6172,7 +6285,6 @@
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();
@@ -6193,9 +6305,9 @@
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();
@@ -6204,6 +6316,7 @@
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();
@@ -6220,6 +6333,7 @@
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);
@@ -6243,7 +6357,6 @@
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
@@ -6318,18 +6431,6 @@
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();
@@ -6357,7 +6458,7 @@
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();
@@ -6368,9 +6469,9 @@
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;
}
@@ -6384,8 +6485,8 @@
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();
@@ -6611,11 +6712,13 @@
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);
@@ -6624,7 +6727,9 @@
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);
@@ -7199,12 +7304,20 @@
public class ProvisioningManager {
method public static android.telephony.ims.ProvisioningManager createForSubscriptionId(android.content.Context, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
+ method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+ method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningIntValue(int, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningStringValue(int, String);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
+ field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
+ field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
+ field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
+ field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
+ field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
}
public static class ProvisioningManager.Callback {
diff --git a/api/test-current.txt b/api/test-current.txt
index 03692e9..af455fb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -613,6 +613,7 @@
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 +622,9 @@
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 +634,7 @@
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 +647,7 @@
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 +658,7 @@
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -669,11 +676,75 @@
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 +905,26 @@
}
+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 {
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index 1315750..deebd4e 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 38130c8..5fd148e 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -23,9 +23,11 @@
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";
@@ -134,6 +136,31 @@
BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
+ NfcErrorOccurred nfc_error_occurred = 134;
+ NfcStateChanged nfc_state_changed = 135;
+ NfcBeamOccurred nfc_beam_occurred = 136;
+ NfcCardemulationOccurred nfc_cardemulation_occurred = 137;
+ NfcTagOccurred nfc_tag_occurred = 138;
+ 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.
@@ -1076,6 +1103,27 @@
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
@@ -1159,6 +1207,516 @@
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.
@@ -2236,3 +2794,138 @@
// See definition in data_stall_event.proto.
optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES];
}
+
+/**
+ * Logs when a NFC device's error occurred.
+ * Logged from:
+ * system/nfc/src/nfc/nfc/nfc_ncif.cc
+ * packages/apps/Nfc/src/com/android/nfc/cardemulation/AidRoutingManager.java
+ */
+message NfcErrorOccurred {
+ enum Type {
+ UNKNOWN = 0;
+ CMD_TIMEOUT = 1;
+ ERROR_NOTIFICATION = 2;
+ AID_OVERFLOW = 3;
+ }
+ optional Type type = 1;
+ // If it's nci cmd timeout, log the timeout command.
+ optional uint32 nci_cmd = 2;
+
+ optional uint32 error_ntf_status_code = 3;
+}
+
+/**
+ * Logs when a NFC device's state changed event
+ * Logged from:
+ * packages/apps/Nfc/src/com/android/nfc/NfcService.java
+ */
+message NfcStateChanged {
+ enum State {
+ UNKNOWN = 0;
+ OFF = 1;
+ ON = 2;
+ ON_LOCKED = 3; // Secure Nfc enabled.
+ CRASH_RESTART = 4; // NfcService watchdog timeout restart.
+ }
+ optional State state = 1;
+}
+
+/**
+ * Logs when a NFC Beam Transaction occurred.
+ * Logged from:
+ * packages/apps/Nfc/src/com/android/nfc/P2pLinkManager.java
+ */
+message NfcBeamOccurred {
+ enum Operation {
+ UNKNOWN = 0;
+ SEND = 1;
+ RECEIVE = 2;
+ }
+ optional Operation operation = 1;
+}
+
+/**
+ * Logs when a NFC Card Emulation Transaction occurred.
+ * Logged from:
+ * packages/apps/Nfc/src/com/android/nfc/cardemulation/HostEmulationManager.java
+ * packages/apps/Nfc/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java
+ */
+message NfcCardemulationOccurred {
+ enum Category {
+ UNKNOWN = 0;
+ HCE_PAYMENT = 1;
+ HCE_OTHER = 2;
+ OFFHOST = 3;
+ }
+ // Transaction belongs to HCE payment or HCE other category, or offhost.
+ optional Category category = 1;
+ // SeName from transaction: SIMx, eSEx, HCE, HCEF.
+ optional string se_name = 2;
+}
+
+/**
+ * Logs when a NFC Tag event occurred.
+ * Logged from:
+ * packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java
+ */
+message NfcTagOccurred {
+ enum Type {
+ UNKNOWN = 0;
+ URL = 1;
+ BT_PAIRING = 2;
+ PROVISION = 3;
+ WIFI_CONNECT = 4;
+ APP_LAUNCH = 5;
+ OTHERS = 6;
+ }
+ optional Type type = 1;
+}
+
+/**
+ * Logs when Hce transaction triggered
+ * Logged from:
+ * system/nfc/src/nfc/nfc/nfc_ncif.cc
+ */
+message NfcHceTransactionOccurred {
+ // The latency period(in microseconds) it took for the first HCE data
+ // exchange.
+ optional uint32 latency_micros = 1;
+}
+
+/**
+ * Logs when SecureElement state event changed
+ * Logged from:
+ * packages/apps/SecureElement/src/com/android/se/Terminal.java
+ */
+message SeStateChanged {
+ enum State {
+ UNKNOWN = 0;
+ INITIALIZED = 1;
+ DISCONNECTED = 2;
+ CONNECTED = 3;
+ HALCRASH = 4;
+ }
+ optional State state = 1;
+
+ optional string state_change_reason = 2;
+ // SIMx or eSEx.
+ optional string terminal = 3;
+}
+
+/**
+ * Logs when Omapi API used
+ * Logged from:
+ * packages/apps/SecureElement/src/com/android/se/Terminal.java
+ */
+message SeOmapiReported {
+ enum Operation {
+ UNKNOWN = 0;
+ OPEN_CHANNEL = 1;
+ }
+ optional Operation operation = 1;
+ // SIMx or eSEx.
+ optional string terminal = 2;
+
+ optional string package_name = 3;
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4f17447..af451c2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -72,9 +72,7 @@
import android.hardware.display.DisplayManagerGlobal;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
-import android.net.Network;
import android.net.Proxy;
-import android.net.ProxyInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -1005,15 +1003,10 @@
NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
}
- public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
+ public void updateHttpProxy() {
final ConnectivityManager cm = ConnectivityManager.from(
getApplication() != null ? getApplication() : getSystemContext());
- final Network network = cm.getBoundNetworkForProcess();
- if (network != null) {
- Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
- } else {
- Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
- }
+ Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
}
public void processInBackground() {
@@ -5850,8 +5843,7 @@
// crash if we can't get it.
final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
- final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
- Proxy.setHttpProxySystemProperty(proxyInfo);
+ Proxy.setHttpProxySystemProperty(service.getProxyForNetwork(null));
} catch (RemoteException e) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index ae9b83e..cbd85f5 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -99,8 +99,7 @@
void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
in String[] args);
void clearDnsCache();
- void setHttpProxy(in String proxy, in String port, in String exclList,
- in Uri pacFileUrl);
+ void updateHttpProxy();
void setCoreSettings(in Bundle coreSettings);
void updatePackageCompatibilityInfo(in String pkg, in CompatibilityInfo info);
void scheduleTrimMemory(int level);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d2f2468..b2951df 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -84,6 +84,7 @@
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 @@
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 1b08ecd..18a006f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4464,11 +4464,16 @@
}
/**
+ * 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 @@
* {@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 @@
}
/**
+ * 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 37508cd..0046302 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -182,8 +182,10 @@
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/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 7a29c27..2803856 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -532,6 +532,28 @@
"android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
/**
+ * Intent to broadcast silence mode changed.
+ * Alway contains the extra field {@link #EXTRA_DEVICE}
+ * Alway contains the extra field {@link #EXTRA_SILENCE_ENABLED}
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi
+ public static final String ACTION_SILENCE_MODE_CHANGED =
+ "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+
+ /**
+ * Used as an extra field in {@link #ACTION_SILENCE_MODE_CHANGED} intent,
+ * contains whether device is in silence mode as boolean.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_SILENCE_ENABLED =
+ "android.bluetooth.device.extra.SILENCE_ENABLED";
+
+ /**
* Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
*
* @hide
@@ -1592,6 +1614,70 @@
}
/**
+ * Set the Bluetooth device silence mode.
+ *
+ * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
+ * is an active device (for A2DP or HFP), the active device for that profile
+ * will be set to null.
+ * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
+ * active device is null, the {@link BluetoothDevice} will be set as the
+ * active device for that profile.
+ * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
+ * If the {@link BluetoothDevice} is set as the active device for A2DP or
+ * HFP, while silence mode is enabled, then the device will exit silence mode.
+ * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
+ * event and HFP AG indicators will be disabled.
+ * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
+ * enter silence mode.
+ *
+ * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ *
+ * @param silence true to enter silence mode, false to exit
+ * @return true on success, false on error.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setSilenceMode(boolean silence) {
+ final IBluetooth service = sService;
+ if (service == null) {
+ return false;
+ }
+ try {
+ if (getSilenceMode() == silence) {
+ return true;
+ }
+ return service.setSilenceMode(this, silence);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setSilenceMode fail", e);
+ return false;
+ }
+ }
+
+ /**
+ * Get the device silence mode status
+ *
+ * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ *
+ * @return true on device in silence mode, otherwise false.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean getSilenceMode() {
+ final IBluetooth service = sService;
+ if (service == null) {
+ return false;
+ }
+ try {
+ return service.getSilenceMode(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getSilenceMode fail", e);
+ return false;
+ }
+ }
+
+ /**
* Sets whether the phonebook access is allowed to this device.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 29161cc..8959540 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3506,6 +3506,16 @@
/**
* 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/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5bb24ba..3bae12e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1014,20 +1014,54 @@
* 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();
}
}
/**
+ * Configures an always-on VPN connection through a specific application.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * <p>The designated package should declare a {@link VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param userId The identifier of the user to set an always-on VPN for.
+ * @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.
+ * @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) {
+ try {
+ return mService.setAlwaysOnVpnPackage(
+ userId, vpnPackage, lockdownEnabled, /* whitelist */ null);
+ } 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 +1070,7 @@
* 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 +1080,36 @@
}
/**
+ * @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 b5d8226..6f9e65f 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 @@
@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 @@
}
/**
+ * @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 void clear() {
- super.clear();
+ ipAddress = null;
+ gateway = null;
+ dnsServers.clear();
+ domains = null;
+ serverAddress = null;
vendorInfo = null;
leaseDuration = 0;
mtu = 0;
@@ -111,20 +154,20 @@
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 @@
/** 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 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 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 @@
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/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e97060a..fd7360f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -125,8 +125,11 @@
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/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index 8b64f1c..e052488 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 @@
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 b996cda..175263f 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -104,6 +104,8 @@
*
* @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 fbd602c..8d779aa 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -176,6 +176,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(InetAddress address, int prefixLength) {
this(address, prefixLength, 0, 0);
this.scope = scopeForUnicastAddress(address);
@@ -199,6 +200,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(String address) {
this(address, 0, 0);
this.scope = scopeForUnicastAddress(this.address);
@@ -212,6 +214,8 @@
* @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 6628701..42db0fd 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -287,7 +287,8 @@
* @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 @@
* @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 2c831de..e04b5fc 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -123,6 +123,8 @@
/**
* @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 d277034..ac6bff0 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -104,10 +104,11 @@
*
* <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 7f4d8cd1..07668a9 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.Locale;
import java.util.TreeSet;
-import android.system.ErrnoException;
-
/**
* Native methods for managing network interfaces.
*
@@ -172,119 +171,37 @@
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);
+ return Inet4AddressUtils.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);
- }
-
- /**
- * 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 @@
* @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 @@
}
/**
- * 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 @@
*/
@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 @@
}
/**
- * 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/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index e926fda..ef2269a 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -39,12 +39,12 @@
*/
public class ProxyInfo implements Parcelable {
- private String mHost;
- private int mPort;
- private String mExclusionList;
- private String[] mParsedExclusionList;
+ private final String mHost;
+ private final int mPort;
+ private final String mExclusionList;
+ private final String[] mParsedExclusionList;
+ private final Uri mPacFileUrl;
- private Uri mPacFileUrl;
/**
*@hide
*/
@@ -96,7 +96,8 @@
public ProxyInfo(String host, int port, String exclList) {
mHost = host;
mPort = port;
- setExclusionList(exclList);
+ mExclusionList = exclList;
+ mParsedExclusionList = parseExclusionList(mExclusionList);
mPacFileUrl = Uri.EMPTY;
}
@@ -107,7 +108,8 @@
public ProxyInfo(Uri pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
- setExclusionList(LOCAL_EXCL_LIST);
+ mExclusionList = LOCAL_EXCL_LIST;
+ mParsedExclusionList = parseExclusionList(mExclusionList);
if (pacFileUrl == null) {
throw new NullPointerException();
}
@@ -121,7 +123,8 @@
public ProxyInfo(String pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
- setExclusionList(LOCAL_EXCL_LIST);
+ mExclusionList = LOCAL_EXCL_LIST;
+ mParsedExclusionList = parseExclusionList(mExclusionList);
mPacFileUrl = Uri.parse(pacFileUrl);
}
@@ -132,13 +135,22 @@
public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
- setExclusionList(LOCAL_EXCL_LIST);
+ mExclusionList = LOCAL_EXCL_LIST;
+ mParsedExclusionList = parseExclusionList(mExclusionList);
if (pacFileUrl == null) {
throw new NullPointerException();
}
mPacFileUrl = pacFileUrl;
}
+ private static String[] parseExclusionList(String exclusionList) {
+ if (exclusionList == null) {
+ return new String[0];
+ } else {
+ return exclusionList.toLowerCase(Locale.ROOT).split(",");
+ }
+ }
+
private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
mHost = host;
mPort = port;
@@ -159,6 +171,10 @@
mExclusionList = source.getExclusionListAsString();
mParsedExclusionList = source.mParsedExclusionList;
} else {
+ mHost = null;
+ mPort = 0;
+ mExclusionList = null;
+ mParsedExclusionList = null;
mPacFileUrl = Uri.EMPTY;
}
}
@@ -214,24 +230,14 @@
return mExclusionList;
}
- // comma separated
- private void setExclusionList(String exclusionList) {
- mExclusionList = exclusionList;
- if (mExclusionList == null) {
- mParsedExclusionList = new String[0];
- } else {
- mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
- }
- }
-
/**
* @hide
*/
public boolean isValid() {
if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
- mPort == 0 ? "" : Integer.toString(mPort),
- mExclusionList == null ? "" : mExclusionList);
+ mPort == 0 ? "" : Integer.toString(mPort),
+ mExclusionList == null ? "" : mExclusionList);
}
/**
@@ -262,7 +268,7 @@
sb.append("] ");
sb.append(Integer.toString(mPort));
if (mExclusionList != null) {
- sb.append(" xl=").append(mExclusionList);
+ sb.append(" xl=").append(mExclusionList);
}
} else {
sb.append("[ProxyProperties.mHost == null]");
@@ -308,8 +314,8 @@
*/
public int hashCode() {
return ((null == mHost) ? 0 : mHost.hashCode())
- + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
- + mPort;
+ + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
+ + mPort;
}
/**
@@ -352,8 +358,7 @@
}
String exclList = in.readString();
String[] parsedExclList = in.readStringArray();
- ProxyInfo proxyProperties =
- new ProxyInfo(host, port, exclList, parsedExclList);
+ ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
return proxyProperties;
}
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 3aa56b9..99cf3a9 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 @@
*
* @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 @@
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 @@
* 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 @@
* 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 @@
return lp;
}
+ @Override
public String toString() {
StringBuffer str = new StringBuffer();
@@ -143,6 +186,7 @@
return str.toString();
}
+ @Override
public int hashCode() {
int result = 13;
result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
@@ -168,12 +212,10 @@
}
/** 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 @@
};
/** 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 bbf8f97..49c6f74 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -128,10 +128,14 @@
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 @@
/** @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 37bf3a7..dc099a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -509,6 +509,15 @@
}
/**
+ * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
+ * and it is possible that some apps will ignore it.
+ */
+ public Builder setHttpProxy(ProxyInfo proxyInfo) {
+ mConfig.proxyInfo = proxyInfo;
+ return this;
+ }
+
+ /**
* Add a network address to the VPN interface. Both IPv4 and IPv6
* addresses are supported. At least one address must be set before
* calling {@link #establish}.
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index f28cdc9..e09fa8f 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 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 1634694..7432687 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 57a926a..7ad4ecf 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -21,21 +21,26 @@
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 @@
* @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 @@
* <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 @@
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 2a942ee..3008115 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -31,10 +31,6 @@
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
similarity index 89%
rename from packages/NetworkStack/src/android/net/util/FdEventsReader.java
rename to core/java/android/net/shared/FdEventsReader.java
index 8bbf449..bffbfb1 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 @@
* 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 @@
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 @@
mBuffer = buffer;
}
+ /** Start this FdEventsReader. */
public void start() {
if (onCorrectThread()) {
createAndRegisterFd();
@@ -100,6 +105,7 @@
}
}
+ /** Stop this FdEventsReader and destroy the file descriptor. */
public void stop() {
if (onCorrectThread()) {
unregisterAndDestroyFd();
@@ -112,22 +118,29 @@
}
@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 @@
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 @@
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 0000000..bec0c84
--- /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 0000000..c9ee3a7
--- /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 de67cf5..fbb15ed 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.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 @@
}
/**
- * 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 6801618..0b2cfdd 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -68,4 +68,8 @@
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 e55e036..a7d2ee9 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -1702,6 +1702,63 @@
}
/**
+ * 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 518528d..3a5b8a8 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 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,55 +49,66 @@
}
/**
- * An interface describing the listener for bugreport progress and status.
+ * An interface describing the callback for bugreport progress and status.
*/
- public interface BugreportListener {
+ public abstract static class BugreportCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
+ BUGREPORT_ERROR_INVALID_INPUT,
+ BUGREPORT_ERROR_RUNTIME,
+ BUGREPORT_ERROR_USER_DENIED_CONSENT,
+ BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT
+ })
+
+ /** Possible error codes taking a bugreport can encounter */
+ public @interface BugreportErrorCode {}
+
+ /** The input options were invalid */
+ public static final int BUGREPORT_ERROR_INVALID_INPUT =
+ IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
+
+ /** A runtime error occured */
+ public static final int BUGREPORT_ERROR_RUNTIME =
+ IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
+
+ /** User denied consent to share the bugreport */
+ public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT =
+ IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
+
+ /** The request to get 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]
*/
- void onProgress(float progress);
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
- BUGREPORT_ERROR_INVALID_INPUT,
- BUGREPORT_ERROR_RUNTIME
- })
-
- /** Possible error codes taking a bugreport can encounter */
- @interface BugreportErrorCode {}
-
- /** The input options were invalid */
- int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
-
- /** A runtime error occured */
- int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
-
- /** User denied consent to share the bugreport */
- int BUGREPORT_ERROR_USER_DENIED_CONSENT =
- IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
+ 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}.
+ * <p>If {@code BUGREPORT_ERROR_USER_DENIED_CONSENT} is passed, then the user did not
+ * consent to sharing the bugreport with the calling app.
+ *
+ * <p>If {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT} is passed, then the consent timed
+ * 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
@@ -106,19 +119,23 @@
* @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();
@@ -139,10 +156,12 @@
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
@@ -152,19 +171,37 @@
@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 4e696ae..3871375 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 @@
*
* @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 53037b24..0000000
--- 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/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 81fc5c0..a89fc09 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -55,6 +55,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
+import java.io.UncheckedIOException;
import java.net.DatagramSocket;
import java.net.Socket;
import java.nio.ByteOrder;
@@ -397,26 +398,41 @@
* @param socket The Socket whose FileDescriptor is used to create
* a new ParcelFileDescriptor.
*
- * @return A new ParcelFileDescriptor with the FileDescriptor of the
- * specified Socket.
+ * @return A new ParcelFileDescriptor with a duped copy of the
+ * FileDescriptor of the specified Socket.
+ *
+ * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
*/
public static ParcelFileDescriptor fromSocket(Socket socket) {
FileDescriptor fd = socket.getFileDescriptor$();
- return fd != null ? new ParcelFileDescriptor(fd) : null;
+ try {
+ return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
/**
- * Create a new ParcelFileDescriptor from the specified DatagramSocket.
+ * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
+ * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
+ * the DatagramSocket, so you must still close the DatagramSocket as well
+ * as the new ParcelFileDescriptor.
*
* @param datagramSocket The DatagramSocket whose FileDescriptor is used
* to create a new ParcelFileDescriptor.
*
- * @return A new ParcelFileDescriptor with the FileDescriptor of the
- * specified DatagramSocket.
+ * @return A new ParcelFileDescriptor with a duped copy of the
+ * FileDescriptor of the specified Socket.
+ *
+ * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
*/
public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
FileDescriptor fd = datagramSocket.getFileDescriptor$();
- return fd != null ? new ParcelFileDescriptor(fd) : null;
+ try {
+ return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
/**
@@ -546,7 +562,7 @@
}
file.deactivate();
FileDescriptor fd = file.getFileDescriptor();
- return fd != null ? new ParcelFileDescriptor(fd) : null;
+ return fd != null ? ParcelFileDescriptor.dup(fd) : null;
}
/**
diff --git a/core/java/android/os/ParcelUuid.java b/core/java/android/os/ParcelUuid.java
index 2c68ddd..5b45ac2 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 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/Process.java b/core/java/android/os/Process.java
index c7afd41..64d14c0 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -498,7 +498,8 @@
String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith,
+ /*useBlastulaPool=*/ true, zygoteArgs);
}
/** @hide */
@@ -515,7 +516,8 @@
String[] zygoteArgs) {
return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
- abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
+ abi, instructionSet, appDataDir, invokeWith,
+ /*useBlastulaPool=*/ false, zygoteArgs);
}
/**
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 94441ca..a96618a 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 @@
* @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/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index f0bdaec..3d28a5e 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -72,6 +72,16 @@
/**
* @hide for internal use only
*/
+ public static final String BLASTULA_POOL_SOCKET_NAME = "blastula_pool";
+
+ /**
+ * @hide for internal use only
+ */
+ public static final String BLASTULA_POOL_SECONDARY_SOCKET_NAME = "blastula_pool_secondary";
+
+ /**
+ * @hide for internal use only
+ */
private static final String LOG_TAG = "ZygoteProcess";
/**
@@ -83,6 +93,15 @@
* The name of the secondary (alternate ABI) zygote socket.
*/
private final LocalSocketAddress mZygoteSecondarySocketAddress;
+ /**
+ * The name of the socket used to communicate with the primary blastula pool.
+ */
+ private final LocalSocketAddress mBlastulaPoolSocketAddress;
+
+ /**
+ * The name of the socket used to communicate with the secondary (alternate ABI) blastula pool.
+ */
+ private final LocalSocketAddress mBlastulaPoolSecondarySocketAddress;
public ZygoteProcess() {
mZygoteSocketAddress =
@@ -90,12 +109,22 @@
mZygoteSecondarySocketAddress =
new LocalSocketAddress(ZYGOTE_SECONDARY_SOCKET_NAME,
LocalSocketAddress.Namespace.RESERVED);
+
+ mBlastulaPoolSocketAddress =
+ new LocalSocketAddress(BLASTULA_POOL_SOCKET_NAME,
+ LocalSocketAddress.Namespace.RESERVED);
+ mBlastulaPoolSecondarySocketAddress =
+ new LocalSocketAddress(BLASTULA_POOL_SECONDARY_SOCKET_NAME,
+ LocalSocketAddress.Namespace.RESERVED);
}
public ZygoteProcess(LocalSocketAddress primarySocketAddress,
LocalSocketAddress secondarySocketAddress) {
mZygoteSocketAddress = primarySocketAddress;
mZygoteSecondarySocketAddress = secondarySocketAddress;
+
+ mBlastulaPoolSocketAddress = null;
+ mBlastulaPoolSecondarySocketAddress = null;
}
public LocalSocketAddress getPrimarySocketAddress() {
@@ -107,6 +136,7 @@
*/
public static class ZygoteState {
final LocalSocketAddress mZygoteSocketAddress;
+ final LocalSocketAddress mBlastulaSocketAddress;
private final LocalSocket mZygoteSessionSocket;
@@ -118,11 +148,13 @@
private boolean mClosed;
private ZygoteState(LocalSocketAddress zygoteSocketAddress,
+ LocalSocketAddress blastulaSocketAddress,
LocalSocket zygoteSessionSocket,
DataInputStream zygoteInputStream,
BufferedWriter zygoteOutputWriter,
List<String> abiList) {
this.mZygoteSocketAddress = zygoteSocketAddress;
+ this.mBlastulaSocketAddress = blastulaSocketAddress;
this.mZygoteSessionSocket = zygoteSessionSocket;
this.mZygoteInputStream = zygoteInputStream;
this.mZygoteOutputWriter = zygoteOutputWriter;
@@ -130,14 +162,17 @@
}
/**
- * Create a new ZygoteState object by connecting to the given Zygote socket.
+ * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
+ * given blastula socket address.
*
* @param zygoteSocketAddress Zygote socket to connect to
+ * @param blastulaSocketAddress Blastula socket address to save for later
* @return A new ZygoteState object containing a session socket for the given Zygote socket
* address
* @throws IOException
*/
- public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress)
+ public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
+ LocalSocketAddress blastulaSocketAddress)
throws IOException {
DataInputStream zygoteInputStream = null;
@@ -150,7 +185,7 @@
zygoteOutputWriter =
new BufferedWriter(
new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
- 256);
+ Zygote.SOCKET_BUFFER_SIZE);
} catch (IOException ex) {
try {
zygoteSessionSocket.close();
@@ -159,11 +194,18 @@
throw ex;
}
- return new ZygoteState(zygoteSocketAddress,
+ return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
getAbiList(zygoteOutputWriter, zygoteInputStream));
}
+ LocalSocket getBlastulaSessionSocket() throws IOException {
+ final LocalSocket blastulaSessionSocket = new LocalSocket();
+ blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
+
+ return blastulaSessionSocket;
+ }
+
boolean matches(String abi) {
return mABIList.contains(abi);
}
@@ -259,12 +301,14 @@
String instructionSet,
String appDataDir,
String invokeWith,
+ boolean useBlastulaPool,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith,
- /*startChildZygote=*/false, zygoteArgs);
+ /*startChildZygote=*/false,
+ useBlastulaPool, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -312,59 +356,127 @@
*/
@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
- ZygoteState zygoteState, ArrayList<String> args)
+ ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
throws ZygoteStartFailedEx {
- try {
- // Throw early if any of the arguments are malformed. This means we can
- // avoid writing a partial response to the zygote.
- int sz = args.size();
- for (int i = 0; i < sz; i++) {
- if (args.get(i).indexOf('\n') >= 0) {
- throw new ZygoteStartFailedEx("embedded newlines not allowed");
+ // Throw early if any of the arguments are malformed. This means we can
+ // avoid writing a partial response to the zygote.
+ for (String arg : args) {
+ if (arg.indexOf('\n') >= 0) {
+ throw new ZygoteStartFailedEx("embedded newlines not allowed");
+ }
+ }
+
+ /**
+ * See com.android.internal.os.SystemZygoteInit.readArgumentList()
+ * Presently the wire format to the zygote process is:
+ * a) a count of arguments (argc, in essence)
+ * b) a number of newline-separated argument strings equal to count
+ *
+ * After the zygote process reads these it will write the pid of
+ * the child or -1 on failure, followed by boolean to
+ * indicate whether a wrapper process was used.
+ */
+ String msgStr = Integer.toString(args.size()) + "\n"
+ + String.join("\n", args) + "\n";
+
+ // Should there be a timeout on this?
+ Process.ProcessStartResult result = new Process.ProcessStartResult();
+
+ // TODO (chriswailes): Move branch body into separate function.
+ if (useBlastulaPool && Zygote.BLASTULA_POOL_ENABLED && isValidBlastulaCommand(args)) {
+ LocalSocket blastulaSessionSocket = null;
+
+ try {
+ blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
+
+ final BufferedWriter blastulaWriter =
+ new BufferedWriter(
+ new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
+ Zygote.SOCKET_BUFFER_SIZE);
+ final DataInputStream blastulaReader =
+ new DataInputStream(blastulaSessionSocket.getInputStream());
+
+ blastulaWriter.write(msgStr);
+ blastulaWriter.flush();
+
+ result.pid = blastulaReader.readInt();
+ // Blastulas can't be used to spawn processes that need wrappers.
+ result.usingWrapper = false;
+
+ if (result.pid < 0) {
+ throw new ZygoteStartFailedEx("Blastula specialization failed");
+ }
+
+ return result;
+ } catch (IOException ex) {
+ // If there was an IOException using the blastula pool we will log the error and
+ // attempt to start the process through the Zygote.
+ Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
+ + ex.toString());
+ } finally {
+ try {
+ blastulaSessionSocket.close();
+ } catch (IOException ex) {
+ Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
}
}
+ }
- /**
- * See com.android.internal.os.SystemZygoteInit.readArgumentList()
- * Presently the wire format to the zygote process is:
- * a) a count of arguments (argc, in essence)
- * b) a number of newline-separated argument strings equal to count
- *
- * After the zygote process reads these it will write the pid of
- * the child or -1 on failure, followed by boolean to
- * indicate whether a wrapper process was used.
- */
- final BufferedWriter writer = zygoteState.mZygoteOutputWriter;
- final DataInputStream inputStream = zygoteState.mZygoteInputStream;
+ try {
+ final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
+ final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
- writer.write(Integer.toString(args.size()));
- writer.newLine();
-
- for (int i = 0; i < sz; i++) {
- String arg = args.get(i);
- writer.write(arg);
- writer.newLine();
- }
-
- writer.flush();
-
- // Should there be a timeout on this?
- Process.ProcessStartResult result = new Process.ProcessStartResult();
+ zygoteWriter.write(msgStr);
+ zygoteWriter.flush();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
- result.pid = inputStream.readInt();
- result.usingWrapper = inputStream.readBoolean();
-
- if (result.pid < 0) {
- throw new ZygoteStartFailedEx("fork() failed");
- }
- return result;
+ result.pid = zygoteInputStream.readInt();
+ result.usingWrapper = zygoteInputStream.readBoolean();
} catch (IOException ex) {
zygoteState.close();
+ Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
+ + ex.toString());
throw new ZygoteStartFailedEx(ex);
}
+
+ if (result.pid < 0) {
+ throw new ZygoteStartFailedEx("fork() failed");
+ }
+
+ return result;
+ }
+
+ /**
+ * Flags that may not be passed to a blastula.
+ */
+ private static final String[] INVALID_BLASTULA_FLAGS = {
+ "--query-abi-list",
+ "--get-pid",
+ "--preload-default",
+ "--preload-package",
+ "--start-child-zygote",
+ "--set-api-blacklist-exemptions",
+ "--hidden-api-log-sampling-rate",
+ "--invoke-with"
+ };
+
+ /**
+ * Tests a command list to see if it is valid to send to a blastula.
+ * @param args Zygote/Blastula command arguments
+ * @return True if the command can be passed to a blastula; false otherwise
+ */
+ private static boolean isValidBlastulaCommand(ArrayList<String> args) {
+ for (String flag : args) {
+ for (String badFlag : INVALID_BLASTULA_FLAGS) {
+ if (flag.startsWith(badFlag)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
/**
@@ -400,6 +512,7 @@
String appDataDir,
String invokeWith,
boolean startChildZygote,
+ boolean useBlastulaPool,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -469,7 +582,9 @@
}
synchronized(mLock) {
- return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
+ return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
+ useBlastulaPool,
+ argsForZygote);
}
}
@@ -633,7 +748,7 @@
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState =
- ZygoteState.connect(mZygoteSocketAddress);
+ ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
@@ -650,7 +765,8 @@
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState =
- ZygoteState.connect(mZygoteSecondarySocketAddress);
+ ZygoteState.connect(mZygoteSecondarySocketAddress,
+ mBlastulaPoolSecondarySocketAddress);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
@@ -737,7 +853,7 @@
for (int n = 20; n >= 0; n--) {
try {
final ZygoteState zs =
- ZygoteState.connect(zygoteSocketAddress);
+ ZygoteState.connect(zygoteSocketAddress, null);
zs.close();
return;
} catch (IOException ioe) {
@@ -778,7 +894,7 @@
result = startViaZygote(processClass, niceName, uid, gid,
gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
- true /* startChildZygote */, extraArgs);
+ true /* startChildZygote */, false /* useBlastulaPool */, extraArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bbd76d2..e904b07 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5671,6 +5671,16 @@
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/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 9bacf9b..f848346 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -64,6 +64,9 @@
private boolean mUseBpfStats;
+ // A persistent Snapshot since device start for eBPF stats
+ private final NetworkStats mPersistSnapshot;
+
// TODO: only do adjustments in NetworkStatsService and remove this.
/**
* (Stacked interface) -> (base interface) association for all connected ifaces since boot.
@@ -135,6 +138,7 @@
mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
mUseBpfStats = useBpfStats;
+ mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
}
public NetworkStats readBpfNetworkStatsDev() throws IOException {
@@ -268,6 +272,7 @@
return stats;
}
+ // TODO: delete the lastStats parameter
private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces,
int limitTag, NetworkStats lastStats) throws IOException {
if (USE_NATIVE_PARSING) {
@@ -278,16 +283,28 @@
} else {
stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
}
- if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
- limitIfaces, limitTag, mUseBpfStats) != 0) {
- throw new IOException("Failed to parse network stats");
+ if (mUseBpfStats) {
+ if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
+ null, TAG_ALL, mUseBpfStats) != 0) {
+ throw new IOException("Failed to parse network stats");
+ }
+ mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
+ mPersistSnapshot.combineAllValues(stats);
+ NetworkStats result = mPersistSnapshot.clone();
+ result.filter(limitUid, limitIfaces, limitTag);
+ return result;
+ } else {
+ if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
+ limitIfaces, limitTag, mUseBpfStats) != 0) {
+ throw new IOException("Failed to parse network stats");
+ }
+ if (SANITY_CHECK_NATIVE) {
+ final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
+ limitIfaces, limitTag);
+ assertEquals(javaStats, stats);
+ }
+ return stats;
}
- if (SANITY_CHECK_NATIVE) {
- final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
- limitIfaces, limitTag);
- assertEquals(javaStats, stats);
- }
- return stats;
} else {
return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index fd03b3f..da8605e 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -28,6 +28,7 @@
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.Network;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -104,6 +105,7 @@
public boolean allowIPv4;
public boolean allowIPv6;
public Network[] underlyingNetworks;
+ public ProxyInfo proxyInfo;
public void updateAllowedFamilies(InetAddress address) {
if (address instanceof Inet4Address) {
@@ -164,6 +166,7 @@
out.writeInt(allowIPv4 ? 1 : 0);
out.writeInt(allowIPv6 ? 1 : 0);
out.writeTypedArray(underlyingNetworks, flags);
+ out.writeParcelable(proxyInfo, flags);
}
public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -189,6 +192,7 @@
config.allowIPv4 = in.readInt() != 0;
config.allowIPv6 = in.readInt() != 0;
config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
+ config.proxyInfo = in.readParcelable(null);
return config;
}
@@ -220,6 +224,7 @@
.append(", allowIPv4=").append(allowIPv4)
.append(", allowIPv6=").append(allowIPv6)
.append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
+ .append(", proxyInfo=").append(proxyInfo.toString())
.append("}")
.toString();
}
diff --git a/core/java/com/android/internal/net/VpnInfo.java b/core/java/com/android/internal/net/VpnInfo.java
index a676dac..b1a41287 100644
--- a/core/java/com/android/internal/net/VpnInfo.java
+++ b/core/java/com/android/internal/net/VpnInfo.java
@@ -32,11 +32,11 @@
@Override
public String toString() {
- return "VpnInfo{" +
- "ownerUid=" + ownerUid +
- ", vpnIface='" + vpnIface + '\'' +
- ", primaryUnderlyingIface='" + primaryUnderlyingIface + '\'' +
- '}';
+ return "VpnInfo{"
+ + "ownerUid=" + ownerUid
+ + ", vpnIface='" + vpnIface + '\''
+ + ", primaryUnderlyingIface='" + primaryUnderlyingIface + '\''
+ + '}';
}
@Override
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 382542a..3859b95 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -16,9 +16,13 @@
package com.android.internal.os;
+import static android.system.OsConstants.O_CLOEXEC;
+
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
import android.os.FactoryTest;
import android.os.IVold;
import android.os.Process;
@@ -30,8 +34,14 @@
import dalvik.system.ZygoteHooks;
+import libcore.io.IoUtils;
+
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.InputStreamReader;
/** @hide */
public final class Zygote {
@@ -92,6 +102,24 @@
/** Read-write external storage should be mounted. */
public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
+ /** Number of bytes sent to the Zygote over blastula pipes or the pool event FD */
+ public static final int BLASTULA_MANAGEMENT_MESSAGE_BYTES = 8;
+
+ /**
+ * If the blastula pool should be created and used to start applications.
+ *
+ * Setting this value to false will disable the creation, maintenance, and use of the blastula
+ * pool. When the blastula pool is disabled the application lifecycle will be identical to
+ * previous versions of Android.
+ */
+ public static final boolean BLASTULA_POOL_ENABLED = false;
+
+ /**
+ * File descriptor used for communication between the signal handler and the ZygoteServer poll
+ * loop.
+ * */
+ protected static FileDescriptor sBlastulaPoolEventFD;
+
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
/**
@@ -101,6 +129,45 @@
*/
public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
+ /** Prefix prepended to socket names created by init */
+ private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
+
+ /**
+ * The maximum value that the sBlastulaPoolMax variable may take. This value
+ * is a mirror of BLASTULA_POOL_MAX_LIMIT found in com_android_internal_os_Zygote.cpp.
+ */
+ static final int BLASTULA_POOL_MAX_LIMIT = 10;
+
+ /**
+ * The minimum value that the sBlastulaPoolMin variable may take.
+ */
+ static final int BLASTULA_POOL_MIN_LIMIT = 1;
+
+ /**
+ * The runtime-adjustable maximum Blastula pool size.
+ */
+ static int sBlastulaPoolMax = BLASTULA_POOL_MAX_LIMIT;
+
+ /**
+ * The runtime-adjustable minimum Blastula pool size.
+ */
+ static int sBlastulaPoolMin = BLASTULA_POOL_MIN_LIMIT;
+
+ /**
+ * The runtime-adjustable value used to determine when to re-fill the
+ * blastula pool. The pool will be re-filled when
+ * (sBlastulaPoolMax - gBlastulaPoolCount) >= sBlastulaPoolRefillThreshold.
+ */
+ // TODO (chriswailes): This must be updated at the same time as sBlastulaPoolMax.
+ static int sBlastulaPoolRefillThreshold = (sBlastulaPoolMax / 2);
+
+ /**
+ * @hide for internal use only
+ */
+ public static final int SOCKET_BUFFER_SIZE = 256;
+
+ private static LocalServerSocket sBlastulaPoolSocket = null;
+
/** a prototype instance for a future List.toArray() */
protected static final int[][] INT_ARRAY_2D = new int[0][0];
@@ -168,6 +235,49 @@
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
String appDataDir);
+ /**
+ * Specialize a Blastula instance. The current VM must have been started
+ * with the -Xzygote flag.
+ *
+ * @param uid The UNIX uid that the new process should setuid() to before spawning any threads
+ * @param gid The UNIX gid that the new process should setgid() to before spawning any threads
+ * @param gids null-ok; A list of UNIX gids that the new process should
+ * setgroups() to before spawning any threads
+ * @param runtimeFlags Bit flags that enable ART features
+ * @param rlimits null-ok An array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param seInfo null-ok A string specifying SELinux information for
+ * the new process.
+ * @param niceName null-ok A string specifying the process name.
+ * @param startChildZygote If true, the new child process will itself be a
+ * new zygote process.
+ * @param instructionSet null-ok The instruction set to use.
+ * @param appDataDir null-ok The data directory of the app.
+ */
+ public static void specializeBlastula(int uid, int gid, int[] gids, int runtimeFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName,
+ boolean startChildZygote, String instructionSet, String appDataDir) {
+
+ nativeSpecializeBlastula(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
+ niceName, startChildZygote, instructionSet, appDataDir);
+
+ // Enable tracing as soon as possible for the child process.
+ Trace.setTracingEnabled(true, runtimeFlags);
+
+ // Note that this event ends at the end of handleChildProc.
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
+
+ /*
+ * This is called here (instead of after the fork but before the specialize) to maintain
+ * consistancy with the code paths for forkAndSpecialize.
+ *
+ * TODO (chriswailes): Look into moving this to immediately after the fork.
+ */
+ VM_HOOKS.postForkCommon();
+ }
+
private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids,
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir);
@@ -230,18 +340,295 @@
*/
protected static native void nativeUnmountStorageOnInit();
+ /**
+ * Get socket file descriptors (opened by init) from the environment and
+ * store them for access from native code later.
+ *
+ * @param isPrimary True if this is the zygote process, false if it is zygote_secondary
+ */
+ public static void getSocketFDs(boolean isPrimary) {
+ nativeGetSocketFDs(isPrimary);
+ }
+
protected static native void nativeGetSocketFDs(boolean isPrimary);
+ /**
+ * Initialize the blastula pool and fill it with the desired number of
+ * processes.
+ */
+ protected static Runnable initBlastulaPool() {
+ if (BLASTULA_POOL_ENABLED) {
+ sBlastulaPoolEventFD = getBlastulaPoolEventFD();
+
+ return fillBlastulaPool(null);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Checks to see if the current policy says that pool should be refilled, and spawns new
+ * blastulas if necessary.
+ *
+ * NOTE: This function doesn't need to be guarded with BLASTULA_POOL_ENABLED because it is
+ * only called from contexts that are only valid if the pool is enabled.
+ *
+ * @param sessionSocketRawFDs Anonymous session sockets that are currently open
+ * @return In the Zygote process this function will always return null; in blastula processes
+ * this function will return a Runnable object representing the new application that is
+ * passed up from blastulaMain.
+ */
+ protected static Runnable fillBlastulaPool(int[] sessionSocketRawFDs) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillBlastulaPool");
+
+ int blastulaPoolCount = getBlastulaPoolCount();
+
+ int numBlastulasToSpawn = sBlastulaPoolMax - blastulaPoolCount;
+
+ if (blastulaPoolCount < sBlastulaPoolMin
+ || numBlastulasToSpawn >= sBlastulaPoolRefillThreshold) {
+
+ // Disable some VM functionality and reset some system values
+ // before forking.
+ VM_HOOKS.preFork();
+ resetNicePriority();
+
+ while (blastulaPoolCount++ < sBlastulaPoolMax) {
+ Runnable caller = forkBlastula(sessionSocketRawFDs);
+
+ if (caller != null) {
+ return caller;
+ }
+ }
+
+ // Re-enable runtime services for the Zygote. Blastula services
+ // are re-enabled in specializeBlastula.
+ VM_HOOKS.postForkCommon();
+
+ Log.i("zygote", "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn);
+ }
+
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+ return null;
+ }
+
+ /**
+ * @return Number of blastulas currently in the pool
+ */
+ private static int getBlastulaPoolCount() {
+ return nativeGetBlastulaPoolCount();
+ }
+
private static native int nativeGetBlastulaPoolCount();
+ /**
+ * @return The event FD used for communication between the signal handler and the ZygoteServer
+ * poll loop
+ */
+ private static FileDescriptor getBlastulaPoolEventFD() {
+ FileDescriptor fd = new FileDescriptor();
+ fd.setInt$(nativeGetBlastulaPoolEventFD());
+
+ return fd;
+ }
+
private static native int nativeGetBlastulaPoolEventFD();
+ /**
+ * Fork a new blastula process from the zygote
+ *
+ * @param sessionSocketRawFDs Anonymous session sockets that are currently open
+ * @return In the Zygote process this function will always return null; in blastula processes
+ * this function will return a Runnable object representing the new application that is
+ * passed up from blastulaMain.
+ */
+ private static Runnable forkBlastula(int[] sessionSocketRawFDs) {
+ FileDescriptor[] pipeFDs = null;
+
+ try {
+ pipeFDs = Os.pipe2(O_CLOEXEC);
+ } catch (ErrnoException errnoEx) {
+ throw new IllegalStateException("Unable to create blastula pipe.", errnoEx);
+ }
+
+ int pid =
+ nativeForkBlastula(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs);
+
+ if (pid == 0) {
+ IoUtils.closeQuietly(pipeFDs[0]);
+ return blastulaMain(pipeFDs[1]);
+ } else {
+ // The read-end of the pipe will be closed by the native code.
+ // See removeBlastulaTableEntry();
+ IoUtils.closeQuietly(pipeFDs[1]);
+ return null;
+ }
+ }
+
private static native int nativeForkBlastula(int readPipeFD,
int writePipeFD,
int[] sessionSocketRawFDs);
+ /**
+ * This function is used by blastulas to wait for specialization requests from the system
+ * server.
+ *
+ * @param writePipe The write end of the reporting pipe used to communicate with the poll loop
+ * of the ZygoteServer.
+ * @return A runnable oject representing the new application.
+ */
+ static Runnable blastulaMain(FileDescriptor writePipe) {
+ final int pid = Process.myPid();
+
+ LocalSocket sessionSocket = null;
+ DataOutputStream blastulaOutputStream = null;
+ Credentials peerCredentials = null;
+ String[] argStrings = null;
+
+ while (true) {
+ try {
+ sessionSocket = sBlastulaPoolSocket.accept();
+
+ BufferedReader blastulaReader =
+ new BufferedReader(new InputStreamReader(sessionSocket.getInputStream()));
+ blastulaOutputStream =
+ new DataOutputStream(sessionSocket.getOutputStream());
+
+ peerCredentials = sessionSocket.getPeerCredentials();
+
+ argStrings = readArgumentList(blastulaReader);
+
+ if (argStrings != null) {
+ break;
+ } else {
+ Log.e("Blastula", "Truncated command received.");
+ IoUtils.closeQuietly(sessionSocket);
+ }
+ } catch (IOException ioEx) {
+ Log.e("Blastula", "Failed to read command: " + ioEx.getMessage());
+ IoUtils.closeQuietly(sessionSocket);
+ }
+ }
+
+ ZygoteArguments args = new ZygoteArguments(argStrings);
+
+ // TODO (chriswailes): Should this only be run for debug builds?
+ validateBlastulaCommand(args);
+
+ applyUidSecurityPolicy(args, peerCredentials);
+ applyDebuggerSystemProperty(args);
+
+ int[][] rlimits = null;
+
+ if (args.mRLimits != null) {
+ rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
+ }
+
+ // This must happen before the SELinux policy for this process is
+ // changed when specializing.
+ try {
+ // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
+ // Process.ProcessStartResult object.
+ blastulaOutputStream.writeInt(pid);
+ } catch (IOException ioEx) {
+ Log.e("Blastula", "Failed to write response to session socket: " + ioEx.getMessage());
+ System.exit(-1);
+ } finally {
+ IoUtils.closeQuietly(sessionSocket);
+ IoUtils.closeQuietly(sBlastulaPoolSocket);
+ }
+
+ try {
+ ByteArrayOutputStream buffer =
+ new ByteArrayOutputStream(Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES);
+ DataOutputStream outputStream = new DataOutputStream(buffer);
+
+ // This is written as a long so that the blastula reporting pipe and blastula pool
+ // event FD handlers in ZygoteServer.runSelectLoop can be unified. These two cases
+ // should both send/receive 8 bytes.
+ outputStream.writeLong(pid);
+ outputStream.flush();
+
+ Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
+ } catch (Exception ex) {
+ Log.e("Blastula",
+ String.format("Failed to write PID (%d) to pipe (%d): %s",
+ pid, writePipe.getInt$(), ex.getMessage()));
+ System.exit(-1);
+ } finally {
+ IoUtils.closeQuietly(writePipe);
+ }
+
+ specializeBlastula(args.mUid, args.mGid, args.mGids,
+ args.mRuntimeFlags, rlimits, args.mMountExternal,
+ args.mSeInfo, args.mNiceName, args.mStartChildZygote,
+ args.mInstructionSet, args.mAppDataDir);
+
+ if (args.mNiceName != null) {
+ Process.setArgV0(args.mNiceName);
+ }
+
+ // End of the postFork event.
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+ return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
+ args.mRemainingArgs,
+ null /* classLoader */);
+ }
+
+ private static final String BLASTULA_ERROR_PREFIX = "Invalid command to blastula: ";
+
+ /**
+ * Checks a set of zygote arguments to see if they can be handled by a blastula. Throws an
+ * exception if an invalid arugment is encountered.
+ * @param args The arguments to test
+ */
+ static void validateBlastulaCommand(ZygoteArguments args) {
+ if (args.mAbiListQuery) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--query-abi-list");
+ } else if (args.mPidQuery) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--get-pid");
+ } else if (args.mPreloadDefault) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--preload-default");
+ } else if (args.mPreloadPackage != null) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--preload-package");
+ } else if (args.mStartChildZygote) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--start-child-zygote");
+ } else if (args.mApiBlacklistExemptions != null) {
+ throw new IllegalArgumentException(
+ BLASTULA_ERROR_PREFIX + "--set-api-blacklist-exemptions");
+ } else if (args.mHiddenApiAccessLogSampleRate != -1) {
+ throw new IllegalArgumentException(
+ BLASTULA_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
+ } else if (args.mInvokeWith != null) {
+ throw new IllegalArgumentException(BLASTULA_ERROR_PREFIX + "--invoke-with");
+ } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
+ throw new ZygoteSecurityException("Client may not specify capabilities: "
+ + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
+ + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
+ }
+ }
+
+ /**
+ * @return Raw file descriptors for the read-end of blastula reporting pipes.
+ */
+ protected static int[] getBlastulaPipeFDs() {
+ return nativeGetBlastulaPipeFDs();
+ }
+
private static native int[] nativeGetBlastulaPipeFDs();
+ /**
+ * Remove the blastula table entry for the provided process ID.
+ *
+ * @param blastulaPID Process ID of the entry to remove
+ * @return True if the entry was removed; false if it doesn't exist
+ */
+ protected static boolean removeBlastulaTableEntry(int blastulaPID) {
+ return nativeRemoveBlastulaTableEntry(blastulaPID);
+ }
+
private static native boolean nativeRemoveBlastulaTableEntry(int blastulaPID);
/**
@@ -385,6 +772,48 @@
return args;
}
+ /**
+ * Creates a managed object representing the Blastula pool socket that has
+ * already been initialized and bound by init.
+ *
+ * TODO (chriswailes): Move the name selection logic into this function.
+ *
+ * @throws RuntimeException when open fails
+ */
+ static void createBlastulaSocket(String socketName) {
+ if (BLASTULA_POOL_ENABLED && sBlastulaPoolSocket == null) {
+ sBlastulaPoolSocket = createManagedSocketFromInitSocket(socketName);
+ }
+ }
+
+ /**
+ * Creates a managed LocalServerSocket object using a file descriptor
+ * created by an init.rc script. The init scripts that specify the
+ * sockets name can be found in system/core/rootdir. The socket is bound
+ * to the file system in the /dev/sockets/ directory, and the file
+ * descriptor is shared via the ANDROID_SOCKET_<socketName> environment
+ * variable.
+ */
+ static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
+ int fileDesc;
+ final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
+
+ try {
+ String env = System.getenv(fullSocketName);
+ fileDesc = Integer.parseInt(env);
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
+ }
+
+ try {
+ FileDescriptor fd = new FileDescriptor();
+ fd.setInt$(fileDesc);
+ return new LocalServerSocket(fd);
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "Error building socket from file descriptor: " + fileDesc, ex);
+ }
+ }
private static void callPostForkSystemServerHooks() {
// SystemServer specific post fork hooks run before child post fork hooks.
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 43f114f..ab356a6 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -224,7 +224,7 @@
fdsToClose[0] = fd.getInt$();
}
- fd = zygoteServer.getServerSocketFileDescriptor();
+ fd = zygoteServer.getZygoteSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 2f00c07..e3e55ed 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -269,7 +269,7 @@
try {
BufferedReader br =
- new BufferedReader(new InputStreamReader(is), 256);
+ new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
int count = 0;
String line;
@@ -750,7 +750,7 @@
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
- final Runnable caller;
+ Runnable caller;
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
@@ -786,7 +786,17 @@
throw new RuntimeException("No ABI list supplied.");
}
- zygoteServer.registerServerSocketFromEnv(socketName);
+ // TODO (chriswailes): Wrap these three calls in a helper function?
+ final String blastulaSocketName =
+ socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME)
+ ? ZygoteProcess.BLASTULA_POOL_SOCKET_NAME
+ : ZygoteProcess.BLASTULA_POOL_SECONDARY_SOCKET_NAME;
+
+ zygoteServer.createZygoteSocket(socketName);
+ Zygote.createBlastulaSocket(blastulaSocketName);
+
+ Zygote.getSocketFDs(socketName.equals(ZygoteProcess.ZYGOTE_SOCKET_NAME));
+
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
@@ -829,11 +839,18 @@
}
}
- Log.i(TAG, "Accepting command socket connections");
+ // If the return value is null then this is the zygote process
+ // returning to the normal control flow. If it returns a Runnable
+ // object then this is a blastula that has finished specializing.
+ caller = Zygote.initBlastulaPool();
- // The select loop returns early in the child process after a fork and
- // loops forever in the zygote.
- caller = zygoteServer.runSelectLoop(abiList);
+ if (caller == null) {
+ Log.i(TAG, "Accepting command socket connections");
+
+ // The select loop returns early in the child process after a fork and
+ // loops forever in the zygote.
+ caller = zygoteServer.runSelectLoop(abiList);
+ }
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index c1bfde1..680d649 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -26,6 +26,8 @@
import android.util.Log;
import android.util.Slog;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList;
@@ -40,18 +42,17 @@
* client protocol.
*/
class ZygoteServer {
+ // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
public static final String TAG = "ZygoteServer";
- private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
-
/**
* Listening socket that accepts new server connections.
*/
- private LocalServerSocket mServerSocket;
+ private LocalServerSocket mZygoteSocket;
/**
- * Whether or not mServerSocket's underlying FD should be closed directly.
- * If mServerSocket is created with an existing FD, closing the socket does
+ * Whether or not mZygoteSocket's underlying FD should be closed directly.
+ * If mZygoteSocket is created with an existing FD, closing the socket does
* not close the FD and it must be closed explicitly. If the socket is created
* with a name instead, then closing the socket will close the underlying FD
* and it should not be double-closed.
@@ -70,31 +71,17 @@
}
/**
- * Registers a server socket for zygote command connections. This locates the server socket
- * file descriptor through an ANDROID_SOCKET_ environment variable.
+ * Creates a managed object representing the Zygote socket that has already
+ * been initialized and bound by init.
+ *
+ * TODO (chriswailes): Move the name selection logic into this function.
*
* @throws RuntimeException when open fails
*/
- void registerServerSocketFromEnv(String socketName) {
- if (mServerSocket == null) {
- int fileDesc;
- final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
- try {
- String env = System.getenv(fullSocketName);
- fileDesc = Integer.parseInt(env);
- } catch (RuntimeException ex) {
- throw new RuntimeException(fullSocketName + " unset or invalid", ex);
- }
-
- try {
- FileDescriptor fd = new FileDescriptor();
- fd.setInt$(fileDesc);
- mServerSocket = new LocalServerSocket(fd);
- mCloseSocketFd = true;
- } catch (IOException ex) {
- throw new RuntimeException(
- "Error binding to local socket '" + fileDesc + "'", ex);
- }
+ void createZygoteSocket(String socketName) {
+ if (mZygoteSocket == null) {
+ mZygoteSocket = Zygote.createManagedSocketFromInitSocket(socketName);
+ mCloseSocketFd = true;
}
}
@@ -103,9 +90,9 @@
* at the specified name in the abstract socket namespace.
*/
void registerServerSocketAtAbstractName(String socketName) {
- if (mServerSocket == null) {
+ if (mZygoteSocket == null) {
try {
- mServerSocket = new LocalServerSocket(socketName);
+ mZygoteSocket = new LocalServerSocket(socketName);
mCloseSocketFd = false;
} catch (IOException ex) {
throw new RuntimeException(
@@ -120,7 +107,7 @@
*/
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
- return createNewConnection(mServerSocket.accept(), abiList);
+ return createNewConnection(mZygoteSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
@@ -138,9 +125,9 @@
*/
void closeServerSocket() {
try {
- if (mServerSocket != null) {
- FileDescriptor fd = mServerSocket.getFileDescriptor();
- mServerSocket.close();
+ if (mZygoteSocket != null) {
+ FileDescriptor fd = mZygoteSocket.getFileDescriptor();
+ mZygoteSocket.close();
if (fd != null && mCloseSocketFd) {
Os.close(fd);
}
@@ -151,7 +138,7 @@
Log.e(TAG, "Zygote: error closing descriptor", ex);
}
- mServerSocket = null;
+ mZygoteSocket = null;
}
/**
@@ -160,8 +147,8 @@
* closure after a child process is forked off.
*/
- FileDescriptor getServerSocketFileDescriptor() {
- return mServerSocket.getFileDescriptor();
+ FileDescriptor getZygoteSocketFileDescriptor() {
+ return mZygoteSocket.getFileDescriptor();
}
/**
@@ -170,36 +157,67 @@
* worth at a time.
*/
Runnable runSelectLoop(String abiList) {
- ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
+ ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
- fds.add(mServerSocket.getFileDescriptor());
+ socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
while (true) {
- StructPollfd[] pollFds = new StructPollfd[fds.size()];
- for (int i = 0; i < pollFds.length; ++i) {
- pollFds[i] = new StructPollfd();
- pollFds[i].fd = fds.get(i);
- pollFds[i].events = (short) POLLIN;
+ int[] blastulaPipeFDs = Zygote.getBlastulaPipeFDs();
+
+ // Space for all of the socket FDs, the Blastula Pool Event FD, and
+ // all of the open blastula read pipe FDs.
+ StructPollfd[] pollFDs =
+ new StructPollfd[socketFDs.size() + 1 + blastulaPipeFDs.length];
+
+ int pollIndex = 0;
+ for (FileDescriptor socketFD : socketFDs) {
+ pollFDs[pollIndex] = new StructPollfd();
+ pollFDs[pollIndex].fd = socketFD;
+ pollFDs[pollIndex].events = (short) POLLIN;
+ ++pollIndex;
}
+
+ final int blastulaPoolEventFDIndex = pollIndex;
+ pollFDs[pollIndex] = new StructPollfd();
+ pollFDs[pollIndex].fd = Zygote.sBlastulaPoolEventFD;
+ pollFDs[pollIndex].events = (short) POLLIN;
+ ++pollIndex;
+
+ for (int blastulaPipeFD : blastulaPipeFDs) {
+ FileDescriptor managedFd = new FileDescriptor();
+ managedFd.setInt$(blastulaPipeFD);
+
+ pollFDs[pollIndex] = new StructPollfd();
+ pollFDs[pollIndex].fd = managedFd;
+ pollFDs[pollIndex].events = (short) POLLIN;
+ ++pollIndex;
+ }
+
try {
- Os.poll(pollFds, -1);
+ Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
- for (int i = pollFds.length - 1; i >= 0; --i) {
- if ((pollFds[i].revents & POLLIN) == 0) {
+
+ while (--pollIndex >= 0) {
+ if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
- if (i == 0) {
+ if (pollIndex == 0) {
+ // Zygote server socket
+
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
- fds.add(newPeer.getFileDescriptor());
- } else {
+ socketFDs.add(newPeer.getFileDescriptor());
+
+ } else if (pollIndex < blastulaPoolEventFDIndex) {
+ // Session socket accepted from the Zygote server socket
+
try {
- ZygoteConnection connection = peers.get(i);
+ ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
@@ -217,12 +235,12 @@
}
// We don't know whether the remote side of the socket was closed or
- // not until we attempt to read from it from processOneCommand. This shows up as
- // a regular POLLIN event in our regular processing loop.
+ // not until we attempt to read from it from processOneCommand. This
+ // shows up as a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
- peers.remove(i);
- fds.remove(i);
+ peers.remove(pollIndex);
+ socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
@@ -234,13 +252,13 @@
Slog.e(TAG, "Exception executing zygote command: ", e);
- // Make sure the socket is closed so that the other end knows immediately
- // that something has gone wrong and doesn't time out waiting for a
- // response.
- ZygoteConnection conn = peers.remove(i);
+ // Make sure the socket is closed so that the other end knows
+ // immediately that something has gone wrong and doesn't time out
+ // waiting for a response.
+ ZygoteConnection conn = peers.remove(pollIndex);
conn.closeSocket();
- fds.remove(i);
+ socketFDs.remove(pollIndex);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
@@ -254,6 +272,55 @@
// is returned.
mIsForkChild = false;
}
+ } else {
+ // Either the blastula pool event FD or a blastula reporting pipe.
+
+ // If this is the event FD the payload will be the number of blastulas removed.
+ // If this is a reporting pipe FD the payload will be the PID of the blastula
+ // that was just specialized.
+ long messagePayload = -1;
+
+ try {
+ byte[] buffer = new byte[Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES];
+ int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
+
+ if (readBytes == Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES) {
+ DataInputStream inputStream =
+ new DataInputStream(new ByteArrayInputStream(buffer));
+
+ messagePayload = inputStream.readLong();
+ } else {
+ Log.e(TAG, "Incomplete read from blastula management FD of size "
+ + readBytes);
+ continue;
+ }
+ } catch (Exception ex) {
+ if (pollIndex == blastulaPoolEventFDIndex) {
+ Log.e(TAG, "Failed to read from blastula pool event FD: "
+ + ex.getMessage());
+ } else {
+ Log.e(TAG, "Failed to read from blastula reporting pipe: "
+ + ex.getMessage());
+ }
+
+ continue;
+ }
+
+ if (pollIndex > blastulaPoolEventFDIndex) {
+ Zygote.removeBlastulaTableEntry((int) messagePayload);
+ }
+
+ int[] sessionSocketRawFDs =
+ socketFDs.subList(1, socketFDs.size())
+ .stream()
+ .mapToInt(fd -> fd.getInt$())
+ .toArray();
+
+ final Runnable command = Zygote.fillBlastulaPool(sessionSocketRawFDs);
+
+ if (command != null) {
+ return command;
+ }
}
}
}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index e5ad1f4..7398e95 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 @@
* 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 @@
*
* @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 @@
*
* @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 @@
/**
* 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/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 03a463e..e344f2a 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -551,7 +551,7 @@
// 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 df735ae..42f1a62 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -132,7 +132,7 @@
"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 7738d84..f40b461 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -72,7 +72,7 @@
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 2f25d8f..e22f581 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -54,7 +54,7 @@
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 190ddce..3ff2446 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -134,7 +134,7 @@
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 d953aee..b885c28 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -49,7 +49,7 @@
{
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 8df028a..8be617f 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -943,7 +943,7 @@
}
/* 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_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 6f9cc22..de30773 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -37,7 +37,7 @@
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 adff4d6..9556333 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1158,7 +1158,7 @@
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 6f975b2..578788c 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -40,7 +40,7 @@
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 62aa1f38..9782541 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 5eefc81..dc536b2 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -125,7 +125,7 @@
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 @@
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 24bafca..8259ffc 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -95,7 +95,7 @@
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 43e6399..1448d7b 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 @@
// 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 @@
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)));
}
}
}
@@ -1252,7 +1252,7 @@
fds_to_close.insert(fds_to_close.end(), blastula_pipes.begin(), blastula_pipes.end());
fds_to_ignore.insert(fds_to_ignore.end(), blastula_pipes.begin(), blastula_pipes.end());
-// fds_to_close.push_back(gBlastulaPoolSocketFD);
+ fds_to_close.push_back(gBlastulaPoolSocketFD);
if (gBlastulaPoolEventFD != -1) {
fds_to_close.push_back(gBlastulaPoolEventFD);
@@ -1277,7 +1277,7 @@
std::vector<int> fds_to_close(MakeBlastulaPipeReadFDVector()),
fds_to_ignore(fds_to_close);
-// fds_to_close.push_back(gBlastulaPoolSocketFD);
+ fds_to_close.push_back(gBlastulaPoolSocketFD);
if (gBlastulaPoolEventFD != -1) {
fds_to_close.push_back(gBlastulaPoolEventFD);
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 0ed8c0c..8e6db0b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -71,6 +71,7 @@
return true;
}
+ // Framework jars are allowed.
static const char* kFrameworksPrefix = "/system/framework/";
static const char* kJarSuffix = ".jar";
if (android::base::StartsWith(path, kFrameworksPrefix)
@@ -78,6 +79,13 @@
return true;
}
+ // Jars from the runtime apex are allowed.
+ static const char* kRuntimeApexPrefix = "/apex/com.android.runtime/javalib/";
+ if (android::base::StartsWith(path, kRuntimeApexPrefix)
+ && android::base::EndsWith(path, kJarSuffix)) {
+ return true;
+ }
+
// Whitelist files needed for Runtime Resource Overlay, like these:
// /system/vendor/overlay/framework-res.apk
// /system/vendor/overlay-subdir/pg/framework-res.apk
@@ -410,13 +418,13 @@
}
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 80cc2d4..3b891d6 100644
--- a/core/proto/Android.bp
+++ b/core/proto/Android.bp
@@ -21,7 +21,10 @@
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 0000000..5a025bd
--- /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 76c240e..a88a06c 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -56,3 +56,57 @@
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 e1d96bb..ef894e5 100644
--- a/core/proto/android/bluetooth/hci/enums.proto
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -351,7 +351,7 @@
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 @@
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 0000000..c6747b7
--- /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 344b74c..2f3c1db 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -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 041fb7e..3a9d9a3 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -51,7 +51,6 @@
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/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 0906435..104208e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -38,7 +38,6 @@
import android.content.pm.ServiceInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
-import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -499,7 +498,7 @@
}
@Override
- public void setHttpProxy(String s, String s1, String s2, Uri uri) throws RemoteException {
+ public void updateHttpProxy() throws RemoteException {
}
@Override
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ddab252..212c723 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -512,6 +512,7 @@
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 7e20f2d..d03e5e3 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.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;
@@ -65,12 +63,11 @@
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 +78,7 @@
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),
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index a2da0a0..b0522f2 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 0000000..55ba591
--- /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 50c4dfc..4fa7d64 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_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.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.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.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 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 @@
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 @@
// 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 04ac9a3..b0e8da9 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_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_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.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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
// 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 0d298de..0a15cd7 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 @@
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 ce8b7e7..d7ff98b1 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 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 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 @@
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 dce8b61..96d1a28 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
@@ -18,7 +18,7 @@
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 @@
@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 7b112df..cd993e9 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.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.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 @@
@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 @@
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 @@
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 @@
}
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 @@
// 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 868f3be..3cd2aa4 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.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 @@
*/
@NonNull
public Inet4Address getBroadcastAddress() {
- return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
+ return Inet4AddressUtils.getBroadcastAddress(
+ getServerInet4Addr(), serverAddr.getPrefixLength());
}
/**
@@ -208,7 +209,7 @@
* 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 @@
* 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 @@
* 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 @@
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 385dd52..649257a 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.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.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 @@
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 @@
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 ad7f85d..12fe8c5 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.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.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.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 @@
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 @@
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 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 @@
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 @@
// 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 @@
}
@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 @@
}
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 @@
// 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 @@
// - 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 0000000..8ad99aa0
--- /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 eb993a4..b29d617 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.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.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.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 @@
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 @@
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 @@
}
} catch (ErrnoException|SocketException e) {
logError("Failed to create rtnetlink socket", e);
- IoUtils.closeQuietly(fd);
+ NetworkStackUtils.closeSocketQuietly(fd);
return null;
}
@@ -186,7 +188,7 @@
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 761db68..76a0338 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.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 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/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
new file mode 100644
index 0000000..98123a5
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -0,0 +1,43 @@
+/*
+ * 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.util;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * Collection of utilities for the network stack.
+ */
+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;
+ }
+
+ /**
+ * 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 4aec6b6..94b1e9f 100644
--- a/packages/NetworkStack/src/android/net/util/PacketReader.java
+++ b/packages/NetworkStack/src/android/net/util/PacketReader.java
@@ -18,6 +18,7 @@
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 0000000..cccec0b
--- /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 0000000..6fb4b0d
--- /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 4080ddf..cedcb84 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -19,6 +19,7 @@
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.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 @@
*/
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 @@
* <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 @@
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 @@
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 @@
}
@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 6b31b82..f21561f 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_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.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.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.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 @@
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 @@
// we can ever fetch them.
// TODO: Delete ASAP.
mLinkProperties = new LinkProperties();
- mNetworkCapabilities = new NetworkCapabilities();
- mNetworkCapabilities.clearAll();
+ mNetworkCapabilities = new NetworkCapabilities(null);
}
/**
@@ -1146,7 +1145,10 @@
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 +1171,7 @@
}
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 eedaf30..804765e 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 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 51d50d9..4abd77e 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.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 @@
@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 @@
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 @@
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 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 @@
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 @@
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 @@
@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 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 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 @@
@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 @@
// 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 @@
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 @@
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 @@
*/
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 a592809..7544e72 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.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.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 @@
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 3ca0564..1004382 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 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 @@
}
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 f21809f..7e57d1e 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.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 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 @@
@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 @@
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 @@
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 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 @@
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 @@
@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 @@
// 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 dced743..6e11c40 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.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.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 @@
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 d31fa77..d11bb64 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.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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8b32afb..c8e5d2b 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.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.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;
@@ -515,7 +516,8 @@
// A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
// the world when it changes.
- private final ProxyTracker mProxyTracker;
+ @VisibleForTesting
+ protected final ProxyTracker mProxyTracker;
final private SettingsObserver mSettingsObserver;
@@ -824,7 +826,7 @@
mPolicyManagerInternal = checkNotNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
- mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
+ mProxyTracker = makeProxyTracker();
mNetd = NetdService.getInstance();
mKeyStore = KeyStore.getInstance();
@@ -990,6 +992,11 @@
deps);
}
+ @VisibleForTesting
+ protected ProxyTracker makeProxyTracker() {
+ return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
+ }
+
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1878,6 +1885,12 @@
"ConnectivityService");
}
+ private void enforceControlAlwaysOnVpnPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+ "ConnectivityService");
+ }
+
private void enforceNetworkStackSettingsOrSetup() {
enforceAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -1885,6 +1898,12 @@
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);
@@ -3724,20 +3743,46 @@
}
}
+ /**
+ * Returns information about the proxy a certain network is using. If given a null network, it
+ * it will return the proxy for the bound network for the caller app or the default proxy if
+ * none.
+ *
+ * @param network the network we want to get the proxy information for.
+ * @return Proxy information if a network has a proxy configured, or otherwise null.
+ */
@Override
public ProxyInfo getProxyForNetwork(Network network) {
- if (network == null) return mProxyTracker.getDefaultProxy();
final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy();
if (globalProxy != null) return globalProxy;
- if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null;
- // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
- // caller may not have.
+ if (network == null) {
+ // Get the network associated with the calling UID.
+ final Network activeNetwork = getActiveNetworkForUidInternal(Binder.getCallingUid(),
+ true);
+ if (activeNetwork == null) {
+ return null;
+ }
+ return getLinkPropertiesProxyInfo(activeNetwork);
+ } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
+ // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
+ // caller may not have.
+ return getLinkPropertiesProxyInfo(network);
+ }
+ // No proxy info available if the calling UID does not have network access.
+ return null;
+ }
+
+ @VisibleForTesting
+ protected boolean queryUserAccess(int uid, int netId) {
+ return NetworkUtils.queryUserAccess(uid, netId);
+ }
+
+ private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai == null) return null;
synchronized (nai) {
- final ProxyInfo proxyInfo = nai.linkProperties.getHttpProxy();
- if (proxyInfo == null) return null;
- return new ProxyInfo(proxyInfo);
+ final ProxyInfo linkHttpProxy = nai.linkProperties.getHttpProxy();
+ return linkHttpProxy == null ? null : new ProxyInfo(linkHttpProxy);
}
}
@@ -3761,11 +3806,10 @@
mProxyTracker.setDefaultProxy(proxy);
}
- // If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy.
- // This method gets called when any network changes proxy, but the broadcast only ever contains
- // the default proxy (even if it hasn't changed).
- // TODO: Deprecate the broadcast extras as they aren't necessarily applicable in a multi-network
- // world where an app might be bound to a non-default network.
+ // If the proxy has changed from oldLp to newLp, resend proxy broadcast. This method gets called
+ // when any network changes proxy.
+ // TODO: Remove usage of broadcast extras as they are deprecated and not applicable in a
+ // multi-network world where an app might be bound to a non-default network.
private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
@@ -4116,8 +4160,9 @@
}
@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) {
@@ -4131,11 +4176,11 @@
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;
}
}
@@ -4144,7 +4189,7 @@
@Override
public String getAlwaysOnVpnPackage(int userId) {
- enforceConnectivityInternalPermission();
+ enforceControlAlwaysOnVpnPermission();
enforceCrossUserPermission(userId);
synchronized (mVpns) {
@@ -4158,6 +4203,36 @@
}
@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;
@@ -4386,7 +4461,7 @@
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);
}
}
}
@@ -4938,8 +5013,8 @@
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);
}
@@ -5932,12 +6007,6 @@
}
scheduleUnvalidatedPrompt(networkAgent);
- if (networkAgent.isVPN()) {
- // Temporarily disable the default proxy (not global).
- mProxyTracker.setDefaultProxyEnabled(false);
- // TODO: support proxy per network.
- }
-
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
// be communicated to a particular NetworkAgent depends only on the network's immutable,
// capabilities, so it only needs to be done once on initial connect, not every time the
@@ -5956,10 +6025,16 @@
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- mProxyTracker.setDefaultProxyEnabled(true);
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
disconnectAndDestroyNetwork(networkAgent);
+ if (networkAgent.isVPN()) {
+ // As the active or bound network changes for apps, broadcast the default proxy, as
+ // apps may need to update their proxy data. This is called after disconnecting from
+ // VPN to make sure we do not broadcast the old proxy data.
+ // TODO(b/122649188): send the broadcast only to VPN users.
+ mProxyTracker.sendProxyBroadcast();
+ }
} else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
state == NetworkInfo.State.SUSPENDED) {
// going into or coming out of SUSPEND: re-score and notify
@@ -6266,7 +6341,7 @@
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 371276f..126bf65 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.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 7f61dd1..da4df22 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -46,11 +46,11 @@
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.InetAddresses;
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;
@@ -62,7 +62,7 @@
import android.net.RouteInfo;
import android.net.TetherStatsParcel;
import android.net.UidRange;
-import android.net.shared.NetdService;
+import android.net.util.NetdService;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -465,9 +465,12 @@
/**
* Notify our observers of a change in the data activity state of the interface
*/
- private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
+ 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) {
@@ -498,9 +501,6 @@
}
}
- boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
- || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
-
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
@@ -734,10 +734,8 @@
} else {
timestampNanos = timestamp;
}
- mDaemonHandler.post(() -> notifyInterfaceClassActivity(label,
- isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
- : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
- timestampNanos, uid, false));
+ mDaemonHandler.post(() ->
+ notifyInterfaceClassActivity(label, isActive, timestampNanos, uid, false));
}
@Override
@@ -904,9 +902,7 @@
}
boolean isActive = cooked[2].equals("active");
notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
- isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
- : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
- timestampNanos, processUid, false);
+ isActive, timestampNanos, processUid, false);
return true;
// break;
case NetdResponseCode.InterfaceAddressChange:
@@ -1456,8 +1452,7 @@
if (ConnectivityManager.isNetworkTypeMobile(type)) {
mNetworkActive = false;
}
- mDaemonHandler.post(() -> notifyInterfaceClassActivity(type,
- DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+ mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true,
SystemClock.elapsedRealtimeNanos(), -1, false));
}
}
@@ -1481,8 +1476,7 @@
throw new IllegalStateException(e);
}
mActiveIdleTimers.remove(iface);
- mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type,
- DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+ 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 1798f38..cbfcd60 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -206,9 +206,10 @@
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;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f59f188..8e80c74 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2240,17 +2240,6 @@
}
} break;
case UPDATE_HTTP_PROXY_MSG: {
- ProxyInfo proxy = (ProxyInfo)msg.obj;
- String host = "";
- String port = "";
- String exclList = "";
- Uri pacFileUrl = Uri.EMPTY;
- if (proxy != null) {
- host = proxy.getHost();
- port = Integer.toString(proxy.getPort());
- exclList = proxy.getExclusionListAsString();
- pacFileUrl = proxy.getPacFileUrl();
- }
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
@@ -2258,7 +2247,7 @@
// ConnectivityManager and don't have network privileges anyway.
if (r.thread != null && !r.isolated) {
try {
- r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
+ r.thread.updateHttpProxy();
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to update http proxy for: " +
r.info.processName);
@@ -21457,8 +21446,7 @@
mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
break;
case Proxy.PROXY_CHANGE_ACTION:
- ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
+ mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
break;
case android.hardware.Camera.ACTION_NEW_PICTURE:
case android.hardware.Camera.ACTION_NEW_VIDEO:
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index fdddccd..a671287 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -309,22 +309,4 @@
}
}
}
-
- /**
- * Enable or disable the default proxy.
- *
- * This sets the flag for enabling/disabling the default proxy and sends the broadcast
- * if applicable.
- * @param enabled whether the default proxy should be enabled.
- */
- public void setDefaultProxyEnabled(final boolean enabled) {
- synchronized (mProxyLock) {
- if (mDefaultProxyEnabled != enabled) {
- mDefaultProxyEnabled = enabled;
- if (mGlobalProxy == null && mDefaultProxy != null) {
- sendProxyBroadcast();
- }
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c72c9dd..2508844 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 @@
.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
@@ -194,6 +194,12 @@
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
@@ -320,9 +326,9 @@
*
* 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 +425,14 @@
*
* @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 +447,27 @@
*
* @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 +480,18 @@
}
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 +503,6 @@
* @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 +510,13 @@
}
/**
+ * @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 +527,9 @@
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 +546,11 @@
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 +570,7 @@
}
// 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
@@ -793,6 +831,8 @@
}
}
+ lp.setHttpProxy(mConfig.proxyInfo);
+
if (!allowIPv4) {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
}
@@ -1247,9 +1287,10 @@
}
/**
- * 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.
@@ -1265,8 +1306,13 @@
*/
@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();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 0b7c5b9..64641b3 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 @@
}
} 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 @@
}
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 92b4d5f..c2c95e6 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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bf872b7..8948977 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 @@
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 @@
pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
}
- if (PRECOMPILED_LAYOUT_ENABLED) {
+ if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
mArtManagerService.compileLayouts(pkg);
}
@@ -17747,7 +17746,7 @@
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 9ca02ba..a6242e1 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.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 @@
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 863bfd5..a8be07d 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 @@
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/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index c90113f..26f6d74 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -39,37 +39,7 @@
template<typename T>
using Return = ::android::hardware::Return<T>;
-class LightHal {
-private:
- static sp<ILight> sLight;
- static bool sLightInit;
-
- LightHal() {}
-
-public:
- static void disassociate() {
- sLightInit = false;
- sLight = nullptr;
- }
-
- static sp<ILight> associate() {
- if ((sLight == nullptr && !sLightInit) ||
- (sLight != nullptr && !sLight->ping().isOk())) {
- // will return the hal if it exists the first time.
- sLight = ILight::getService();
- sLightInit = true;
-
- if (sLight == nullptr) {
- ALOGE("Unable to get ILight interface.");
- }
- }
-
- return sLight;
- }
-};
-
-sp<ILight> LightHal::sLight = nullptr;
-bool LightHal::sLightInit = false;
+static bool sLightSupported = true;
static bool validate(jint light, jint flash, jint brightness) {
bool valid = true;
@@ -134,7 +104,6 @@
const LightState &state) {
if (!ret.isOk()) {
ALOGE("Failed to issue set light command.");
- LightHal::disassociate();
return;
}
@@ -164,13 +133,11 @@
jint offMS,
jint brightnessMode) {
- if (!validate(light, flashMode, brightnessMode)) {
+ if (!sLightSupported) {
return;
}
- sp<ILight> hal = LightHal::associate();
-
- if (hal == nullptr) {
+ if (!validate(light, flashMode, brightnessMode)) {
return;
}
@@ -180,6 +147,11 @@
{
android::base::Timer t;
+ sp<ILight> hal = ILight::getService();
+ if (hal == nullptr) {
+ sLightSupported = false;
+ return;
+ }
Return<Status> ret = hal->setLight(type, state);
processReturn(ret, type, state);
if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8f5d36a..31e1e35 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 @@
}
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 @@
* @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 @@
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);
}
- ConnectivityManager connectivityManager = (ConnectivityManager)
- mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdown)) {
+
+ 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);
+ }
+ }
+ }
+ // 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 @@
}
@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 @@
}
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 e99dd4f..bbecc63 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.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 @@
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 @@
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 30c7de5..638ec95 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -9,12 +9,6 @@
"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/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
deleted file mode 100644
index cddb91f..0000000
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ /dev/null
@@ -1,29 +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.dhcp;
-
-/**
- * TODO: remove this class after migrating clients.
- */
-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 static final int DHCP_SUCCESS = 1;
- public static final int DHCP_FAILURE = 2;
-}
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
index f068c3a..1fe2328 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 b3af67c..970bc9c 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 @@
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 @@
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 a61c2ef..0000000
--- 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 f7360f5..7910c9a 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.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 2a98d90..16f72bd 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_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 @@
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 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 @@
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 @@
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 bc2373f..4ad7138 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.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.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 @@
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 @@
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 @@
}
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 @@
&& (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 2c368c8..1f0525e 100644
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
@@ -44,11 +44,11 @@
@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 @@
@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 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/NetdService.java b/services/net/java/android/net/util/NetdService.java
similarity index 96%
rename from services/net/java/android/net/shared/NetdService.java
rename to services/net/java/android/net/util/NetdService.java
index be0f5f2..d4cd5bd 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 @@
*/
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 @@
// 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/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 7dc83c3..f5b4308 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/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 7b23061..157f12c 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 @@
* @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 @@
* @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/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 2b99ce1..2d29875 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -50,10 +50,10 @@
}
private CallAttributes(Parcel in) {
- mPreciseCallState = (PreciseCallState) in.readValue(mPreciseCallState.getClass()
- .getClassLoader());
+ mPreciseCallState = (PreciseCallState)
+ in.readValue(PreciseCallState.class.getClassLoader());
mNetworkType = in.readInt();
- mCallQuality = (CallQuality) in.readValue(mCallQuality.getClass().getClassLoader());
+ mCallQuality = (CallQuality) in.readValue(CallQuality.class.getClassLoader());
}
// getters
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
index b27f6b4..cbe62284 100644
--- a/telephony/java/android/telephony/CallQuality.java
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -92,6 +92,10 @@
mCodecType = in.readInt();
}
+ /** @hide **/
+ public CallQuality() {
+ }
+
/**
* Constructor.
*
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index eb010bc..190e82b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -608,11 +608,41 @@
public static final String KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL =
"carrier_promote_wfc_on_call_fail_bool";
- /** Flag specifying whether provisioning is required for VOLTE. */
+ /**
+ * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi
+ * Calling.
+ */
public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
= "carrier_volte_provisioning_required_bool";
/**
+ * Flag indicating whether or not the IMS MmTel UT capability requires carrier provisioning
+ * before it can be set as enabled.
+ *
+ * If true, the UT capability will be set to false for the newly loaded subscription
+ * and will require the carrier provisioning app to set the persistent provisioning result.
+ * If false, the platform will not wait for provisioning status updates for the UT capability
+ * and enable the UT over IMS capability for the subscription when the subscription is loaded.
+ *
+ * The default value for this key is {@code false}.
+ */
+ public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL =
+ "carrier_ut_provisioning_required_bool";
+
+ /**
+ * Flag indicating whether or not the carrier supports Supplementary Services over the UT
+ * interface for this subscription.
+ *
+ * If true, the device will use Supplementary Services over UT when provisioned (see
+ * {@link #KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL}). If false, this device will fallback to
+ * circuit switch for supplementary services and will disable this capability for IMS entirely.
+ *
+ * The default value for this key is {@code true}.
+ */
+ public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL =
+ "carrier_supports_ss_over_ut_bool";
+
+ /**
* Flag specifying if WFC provisioning depends on VoLTE provisioning.
*
* {@code false}: default value; honor actual WFC provisioning state.
@@ -2341,33 +2371,54 @@
"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;
@@ -2405,6 +2456,8 @@
sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
@@ -2735,6 +2788,12 @@
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/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9fee593..af324de 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -701,7 +701,7 @@
* @hide
*/
@SystemApi
- public void onCallAttributesChanged(CallAttributes callAttributes) {
+ public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c89496e..3317876 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -27,6 +27,7 @@
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.NetworkRegistrationState.Domain;
+import android.telephony.NetworkRegistrationState.NRStatus;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -539,7 +540,7 @@
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public int getDataRegState() {
return mDataRegState;
}
@@ -1359,6 +1360,18 @@
}
/**
+ * Get the NR 5G status of the mobile data network.
+ * @return the NR 5G status.
+ * @hide
+ */
+ public @NRStatus int getNrStatus() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) return NetworkRegistrationState.NR_STATUS_NONE;
+ return regState.getNrStatus();
+ }
+
+ /**
* @param nrFrequencyRange the frequency range of 5G NR.
* @hide
*/
@@ -1534,7 +1547,6 @@
}
}
-
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @TelephonyManager.NetworkType int getDataNetworkType() {
@@ -1619,8 +1631,9 @@
/** @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 4e4ef4d..443f908 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -577,10 +577,10 @@
}
/**
- * @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 b9ffd4d..5c86efb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -93,6 +93,7 @@
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 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 */
@@ -3117,14 +3117,8 @@
* 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 +3132,37 @@
}
/**
- * 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
+ * @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,12 +8446,25 @@
}
- /** @hide */
- public String getLocaleFromDefaultSim() {
+ /**
+ * 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.getLocaleFromDefaultSim();
+ return telephony.getSimLocaleForSubscriber(getSubId());
}
} catch (RemoteException ex) {
}
@@ -8453,6 +8472,22 @@
}
/**
+ * TODO delete after SuW migrates to new API.
+ * @hide
+ */
+ public String getLocaleFromDefaultSim() {
+ try {
+ final ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getSimLocaleForSubscriber(getSubId());
+ }
+ } catch (RemoteException ex) {
+ }
+ return null;
+ }
+
+
+ /**
* Requests the modem activity info. The recipient will place the result
* in `result`.
* @param result The object on which the recipient will send the resulting
@@ -8919,6 +8954,9 @@
@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 +8967,7 @@
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 +9060,11 @@
@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 +9981,52 @@
}
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;
+ }
}
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 45e4704..19f357a 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
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 294c79b..3d2fe5f 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -23,6 +23,7 @@
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 @@
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 @@
* @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 @@
* 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 @@
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 @@
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 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 @@
.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 @@
&& 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 @@
@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 @@
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 da4822c..1d196f9 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 @@
*/
@SystemApi
public final class DataProfile implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"TYPE_"},
+ value = {
+ TYPE_COMMON,
+ TYPE_3GPP,
+ TYPE_3GPP2})
+ public @interface DataProfileType {}
- // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network.
+ /** 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 @@
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 @@
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 @@
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 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 @@
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 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 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 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 @@
@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 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 @@
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/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index a94b163..e68256d 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -27,6 +27,7 @@
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 @@
* 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 @@
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 @@
mCountryIso = source.readString();
mMnc = source.readString();
mEmergencyServiceCategoryBitmask = source.readInt();
+ mEmergencyUrns = source.createStringArrayList();
mEmergencyNumberSourceBitmask = source.readInt();
mEmergencyCallRouting = source.readInt();
}
@@ -265,6 +276,7 @@
dest.writeString(mCountryIso);
dest.writeString(mMnc);
dest.writeInt(mEmergencyServiceCategoryBitmask);
+ dest.writeStringList(mEmergencyUrns);
dest.writeInt(mEmergencyNumberSourceBitmask);
dest.writeInt(mEmergencyCallRouting);
}
@@ -322,6 +334,21 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
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 @@
&& 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 @@
@Override
public int hashCode() {
return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
- mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
+ mEmergencyUrns, mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
}
/**
@@ -554,6 +599,7 @@
emergencyNumberList.remove(i--);
}
}
+ Collections.sort(emergencyNumberList);
}
/**
@@ -584,9 +630,18 @@
!= 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 @@
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 9c8d078..59167b7 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -33,6 +33,8 @@
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 @@
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 @@
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 @@
+ ", callType=" + mCallType
+ ", restrictCause=" + mRestrictCause
+ ", mediaProfile=" + mMediaProfile.toString()
- + ", emergencyServiceCategories=" + mEmergencyCallRouting
- + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
+ + ", emergencyServiceCategories=" + mEmergencyServiceCategories
+ + ", emergencyUrns=" + mEmergencyUrns
+ + ", emergencyCallRouting=" + mEmergencyCallRouting
+ + ", emergencyCallTesting=" + mEmergencyCallTesting + " }";
}
@Override
@@ -540,7 +556,9 @@
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 @@
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 @@
}
/**
- * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @EmergencyCallRouting int getEmergencyCallRouting() {
return mEmergencyCallRouting;
}
+
+ /**
+ * Get if the emergency call is for testing purpose.
+ */
+ public boolean isEmergencyCallTesting() {
+ return mEmergencyCallTesting;
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 9414abd..5b2e635 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -86,9 +86,7 @@
/**
* Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
- * @hide
*/
- @SystemApi
public static final int WIFI_MODE_WIFI_PREFERRED = 2;
/**
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index d37198a..086a765 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -21,13 +21,17 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsConfigCallback;
+import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import com.android.internal.telephony.ITelephony;
@@ -38,13 +42,68 @@
* to changes in these configurations.
*
* Note: IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
- * applications and may vary.
+ * applications and may vary. For compatibility purposes, the first 100 integer values used in
+ * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys
+ * previously defined in the Android framework. Some common constants have been defined in this
+ * class to make integrating with other system apps easier. USE WITH CARE!
+ *
+ * To avoid collisions, please use String based configurations when possible:
+ * {@link #setProvisioningStringValue(int, String)} and {@link #getProvisioningStringValue(int)}.
* @hide
*/
@SystemApi
public class ProvisioningManager {
/**
+ * The query from {@link #getProvisioningStringValue(int)} has resulted in an unspecified error.
+ */
+ public static final String STRING_QUERY_RESULT_ERROR_GENERIC =
+ "STRING_QUERY_RESULT_ERROR_GENERIC";
+
+ /**
+ * The query from {@link #getProvisioningStringValue(int)} has resulted in an error because the
+ * ImsService implementation was not ready for provisioning queries.
+ */
+ public static final String STRING_QUERY_RESULT_ERROR_NOT_READY =
+ "STRING_QUERY_RESULT_ERROR_NOT_READY";
+
+ /**
+ * The integer result of provisioning for the queried key is disabled.
+ */
+ public static final int PROVISIONING_VALUE_DISABLED = 0;
+
+ /**
+ * The integer result of provisioning for the queried key is enabled.
+ */
+ public static final int PROVISIONING_VALUE_ENABLED = 1;
+
+
+ /**
+ * Override the user-defined WiFi Roaming enabled setting for this subscription, defined in
+ * {@link SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, for the purposes of provisioning
+ * the subscription for WiFi Calling.
+ *
+ * @see #getProvisioningIntValue(int)
+ * @see #setProvisioningIntValue(int, int)
+ */
+ public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26;
+
+ /**
+ * Override the user-defined WiFi mode for this subscription, defined in
+ * {@link SubscriptionManager#WFC_MODE_CONTENT_URI}, for the purposes of provisioning
+ * this subscription for WiFi Calling.
+ *
+ * Valid values for this key are:
+ * {@link ImsMmTelManager#WIFI_MODE_WIFI_ONLY},
+ * {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, or
+ * {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}.
+ *
+ * @see #getProvisioningIntValue(int)
+ * @see #setProvisioningIntValue(int, int)
+ */
+ public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27;
+
+ /**
* Callback for IMS provisioning changes.
*/
public static class Callback {
@@ -180,10 +239,15 @@
/**
* Query for the integer value associated with the provided key.
+ *
+ * This operation is blocking and should not be performed on the UI thread.
+ *
* @param key An integer that represents the provisioning key, which is defined by the OEM.
- * @return an integer value for the provided key.
+ * @return an integer value for the provided key, or
+ * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist.
* @throws IllegalArgumentException if the key provided was invalid.
*/
+ @WorkerThread
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public int getProvisioningIntValue(int key) {
try {
@@ -195,10 +259,16 @@
/**
* Query for the String value associated with the provided key.
- * @param key An integer that represents the provisioning key, which is defined by the OEM.
- * @return a String value for the provided key, or {@code null} if the key doesn't exist.
+ *
+ * This operation is blocking and should not be performed on the UI thread.
+ *
+ * @param key A String that represents the provisioning key, which is defined by the OEM.
+ * @return a String value for the provided key, {@code null} if the key doesn't exist, or one
+ * of the following error codes: {@link #STRING_QUERY_RESULT_ERROR_GENERIC},
+ * {@link #STRING_QUERY_RESULT_ERROR_NOT_READY}.
* @throws IllegalArgumentException if the key provided was invalid.
*/
+ @WorkerThread
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public String getProvisioningStringValue(int key) {
try {
@@ -210,10 +280,16 @@
/**
* Set the integer value associated with the provided key.
+ *
+ * This operation is blocking and should not be performed on the UI thread.
+ *
+ * Use {@link #setProvisioningStringValue(int, String)} with proper namespacing (to be defined
+ * per OEM or carrier) when possible instead to avoid key collision if needed.
* @param key An integer that represents the provisioning key, which is defined by the OEM.
* @param value a integer value for the provided key.
* @return the result of setting the configuration value.
*/
+ @WorkerThread
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public @ImsConfigImplBase.SetConfigResult int setProvisioningIntValue(int key, int value) {
try {
@@ -226,10 +302,14 @@
/**
* Set the String value associated with the provided key.
*
- * @param key An integer that represents the provisioning key, which is defined by the OEM.
+ * This operation is blocking and should not be performed on the UI thread.
+ *
+ * @param key A String that represents the provisioning key, which is defined by the OEM and
+ * should be appropriately namespaced to avoid collision.
* @param value a String value for the provided key.
* @return the result of setting the configuration value.
*/
+ @WorkerThread
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public @ImsConfigImplBase.SetConfigResult int setProvisioningStringValue(int key,
String value) {
@@ -240,6 +320,55 @@
}
}
+ /**
+ * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+ *
+ * Provisioning may or may not be required, depending on the carrier configuration. If
+ * provisioning is not required for the carrier associated with this subscription or the device
+ * does not support the capability/technology combination specified, this operation will be a
+ * no-op.
+ *
+ * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+ * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+ * @param isProvisioned true if the device is provisioned for UT over IMS, false otherwise.
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setProvisioningStatusForCapability(
+ @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int tech, boolean isProvisioned) {
+ try {
+ getITelephony().setImsProvisioningStatusForCapability(mSubId, capability, tech,
+ isProvisioned);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Get the provisioning status for the IMS MmTel capability specified.
+ *
+ * If provisioning is not required for the queried
+ * {@link MmTelFeature.MmTelCapabilities.MmTelCapability} and
+ * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will
+ * always return {@code true}.
+ *
+ * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+ * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+ * @return true if the device is provisioned for the capability or does not require
+ * provisioning, false if the capability does require provisioning and has not been
+ * provisioned yet.
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean getProvisioningStatusForCapability(
+ @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int tech) {
+ try {
+ return getITelephony().getImsProvisioningStatusForCapability(mSubId, capability, tech);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
private static SubscriptionManager getSubscriptionManager(Context context) {
SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
if (manager == null) {
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 7c793a5..1ee8563 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -97,6 +97,13 @@
public @ImsRegistrationImplBase.ImsRegistrationTech int getRadioTech() {
return radioTech;
}
+
+ @Override
+ public String toString() {
+ return "CapabilityPair{"
+ + "mCapability=" + mCapability
+ + ", radioTech=" + radioTech + '}';
+ }
}
// Pair contains <radio tech, mCapability>
@@ -212,6 +219,13 @@
}
}
+ @Override
+ public String toString() {
+ return "CapabilityChangeRequest{"
+ + "mCapabilitiesToEnable=" + mCapabilitiesToEnable
+ + ", mCapabilitiesToDisable=" + mCapabilitiesToDisable + '}';
+ }
+
/**
* @hide
*/
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 71a2174..4fc6a19 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -277,12 +277,14 @@
* Wi-Fi calling roaming status.
* Value is in Integer format. ON (1), OFF(0).
*/
- public static final int VOICE_OVER_WIFI_ROAMING = 26;
+ public static final int VOICE_OVER_WIFI_ROAMING =
+ ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE;
/**
* Wi-Fi calling modem - WfcModeFeatureValueConstants.
* Value is in Integer format.
*/
- public static final int VOICE_OVER_WIFI_MODE = 27;
+ public static final int VOICE_OVER_WIFI_MODE =
+ ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE;
/**
* VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
* Value is in Integer format.
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 3921cfb..7250eee 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 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 43f83cd..1fb8513 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 @@
* 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 @@
* 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 @@
/**
* 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 3660e03..ceb1919 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 @@
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 @@
}
@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 @@
}
@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 @@
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 @@
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 @@
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/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index db76e9e..a12792a 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.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 @@
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 @@
* 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.
@@ -1756,6 +1766,24 @@
void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback);
/**
+ * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+ */
+ void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
+ boolean isProvisioned);
+
+ /**
+ * Get the provisioning status for the IMS MmTel capability specified.
+ */
+ boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech);
+
+ /** Is the capability and tech flagged as provisioned in the cache */
+ boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech);
+
+ /** Set the provisioning for the capability and tech in the cache */
+ void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech,
+ boolean isProvisioned);
+
+ /**
* Return an integer containing the provisioning value for the specified provisioning key.
*/
int getImsProvisioningInt(int subId, int key);
@@ -1776,7 +1804,29 @@
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();
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 599503c..f901c0e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -192,31 +192,11 @@
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;
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 7641d00..0433f92 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 @@
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 @@
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 @@
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 89c6aed..5723c59 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 @@
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 f6a528a..1c96cac 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.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 @@
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 6801fd9..694e0d9 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 270adf8..5c240589 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 07c453c..fccc7b9 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 3452819..ba6e0f2 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 @@
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 5bb5734..2b5ad37 100644
--- a/tests/net/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/java/android/net/StaticIpConfigurationTest.java
@@ -26,13 +26,13 @@
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 @@
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 0000000..d27a4f9
--- /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 80aac04..f7542a7 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.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 0000000..6da8514
--- /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 14df392..fb4d43c 100644
--- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
+++ b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
@@ -62,7 +62,7 @@
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 b5d5f61..036c5dc 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_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,10 +120,12 @@
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;
import android.net.NetworkUtils;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.SocketKeepalive;
import android.net.UidRange;
@@ -161,6 +164,7 @@
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
@@ -480,8 +484,8 @@
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(
@@ -521,7 +525,8 @@
}
};
- assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+ assertEquals(
+ mNetworkAgent.netId, fromStableParcelable(nmNetworkCaptor.getValue()).netId);
mNmCallbacks = nmCbCaptor.getValue();
try {
@@ -1007,6 +1012,11 @@
}
@Override
+ protected ProxyTracker makeProxyTracker() {
+ return mock(ProxyTracker.class);
+ }
+
+ @Override
protected int reserveNetId() {
while (true) {
final int netId = super.reserveNetId();
@@ -1028,6 +1038,11 @@
}
}
+ @Override
+ protected boolean queryUserAccess(int uid, int netId) {
+ return true;
+ }
+
public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
}
@@ -5132,4 +5147,84 @@
mCellNetworkAgent.sendLinkProperties(lp);
verifyTcpBufferSizeChange(TEST_TCP_BUFFER_SIZES);
}
+
+ @Test
+ public void testGetGlobalProxyForNetwork() {
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
+ when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
+ }
+
+ @Test
+ public void testGetProxyForActiveNetwork() {
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ waitForIdle();
+ assertNull(mService.getProxyForNetwork(null));
+
+ final LinkProperties testLinkProperties = new LinkProperties();
+ testLinkProperties.setHttpProxy(testProxyInfo);
+
+ mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
+ waitForIdle();
+
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+ }
+
+ @Test
+ public void testGetProxyForVPN() {
+ final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+
+ // Set up a WiFi network with no proxy
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ waitForIdle();
+ assertNull(mService.getProxyForNetwork(null));
+
+ // Set up a VPN network with a proxy
+ final int uid = Process.myUid();
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ mMockVpn.setUids(ranges);
+ LinkProperties testLinkProperties = new LinkProperties();
+ testLinkProperties.setHttpProxy(testProxyInfo);
+ vpnNetworkAgent.sendLinkProperties(testLinkProperties);
+ waitForIdle();
+
+ // Connect to VPN with proxy
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ vpnNetworkAgent.connect(true);
+ mMockVpn.connect();
+ waitForIdle();
+
+ // Test that the VPN network returns a proxy, and the WiFi does not.
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+ assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
+
+ // Test that the VPN network returns no proxy when it is set to null.
+ testLinkProperties.setHttpProxy(null);
+ vpnNetworkAgent.sendLinkProperties(testLinkProperties);
+ waitForIdle();
+ assertNull(mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+ assertNull(mService.getProxyForNetwork(null));
+
+ // Set WiFi proxy and check that the vpn proxy is still null.
+ testLinkProperties.setHttpProxy(testProxyInfo);
+ mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
+ waitForIdle();
+ assertNull(mService.getProxyForNetwork(null));
+
+ // Disconnect from VPN and check that the active network, which is now the WiFi, has the
+ // correct proxy setting.
+ vpnNetworkAgent.disconnect();
+ waitForIdle();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0b74d87..5b17224 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -246,17 +246,17 @@
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 +270,11 @@
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 +283,7 @@
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 +297,87 @@
}
@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 +391,7 @@
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 +517,7 @@
.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 +531,7 @@
.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));
}
@@ -583,7 +664,9 @@
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/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
index f2ecef9..e57433a 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -202,9 +202,11 @@
final CountDownLatch latch = new CountDownLatch(1);
functor.accept(latch);
try {
- latch.await(5000, TimeUnit.MILLISECONDS);
+ if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+ fail(timeoutMessage);
+ }
} catch (InterruptedException e) {
- fail(timeoutMessage);
+ fail("Thread was interrupted");
}
}
@@ -314,6 +316,7 @@
assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
assertNull(key);
assertNull(attr);
+ latch.countDown();
})));
}
@@ -383,6 +386,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[5], key);
+ latch.countDown();
})));
// MTU matches key 4 but v4 address matches key 5. The latter is stronger.
@@ -392,6 +396,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[5], key);
+ latch.countDown();
})));
// Closest to key 3 (indeed, identical)
@@ -402,6 +407,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[3], key);
+ latch.countDown();
})));
// Group hint alone must not be strong enough to override the rest
@@ -411,6 +417,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[3], key);
+ latch.countDown();
})));
// Still closest to key 3, though confidence is lower
@@ -421,6 +428,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[3], key);
+ latch.countDown();
})));
// But changing the MTU makes this closer to key 4
@@ -430,6 +438,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(FAKE_KEYS[4], key);
+ latch.countDown();
})));
// MTU alone not strong enough to make this group-close
@@ -441,6 +450,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertNull(key);
+ latch.countDown();
})));
}
@@ -450,6 +460,7 @@
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
status.isSuccess());
assertEquals(sameness, answer.getNetworkSameness());
+ latch.countDown();
})));
}
@@ -488,6 +499,7 @@
+ status.resultCode, status.isSuccess());
assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
assertNull(answer);
+ latch.countDown();
})));
}
}
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 5bc004d..cf85726 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -350,133 +350,133 @@
}
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 @@
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 75c3eba..59e89f5 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -223,6 +223,7 @@
class V2Tokenizer(object):
__slots__ = ["raw"]
+ SIGNATURE_PREFIX = "// Signature format: "
DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.')
STRING_SPECIAL = re.compile(r'["\\]')
@@ -610,8 +611,12 @@
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 9c261d5..3716bf9 100644
--- a/tools/apilint/apilint_test.py
+++ b/tools/apilint/apilint_test.py
@@ -164,6 +164,23 @@
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)