Merge "Add Os.bind, Os.sendTo to public API"
diff --git a/Android.bp b/Android.bp
index 45b6511..8f0c898 100644
--- a/Android.bp
+++ b/Android.bp
@@ -221,6 +221,7 @@
"core/java/android/os/ICancellationSignal.aidl",
"core/java/android/os/IDeviceIdentifiersPolicyService.aidl",
"core/java/android/os/IDeviceIdleController.aidl",
+ "core/java/android/os/IDynamicAndroidService.aidl",
"core/java/android/os/IHardwarePropertiesManager.aidl",
":libincident_aidl",
"core/java/android/os/IMaintenanceActivityListener.aidl",
@@ -601,6 +602,7 @@
":storaged_aidl",
":vold_aidl",
+ ":gsiservice_aidl",
":installd_aidl",
":dumpstate_aidl",
@@ -657,6 +659,7 @@
"frameworks/native/aidl/gui",
"system/core/storaged/binder",
"system/vold/binder",
+ "system/gsid/aidl",
"system/bt/binder",
"system/security/keystore/binder",
],
@@ -667,8 +670,6 @@
exclude_srcs: [
// See comment on framework-atb-backward-compatibility module below
"core/java/android/content/pm/AndroidTestBaseUpdater.java",
- // See comment on framework-oahl-backward-compatibility module below
- "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
],
no_framework_libs: true,
@@ -676,7 +677,7 @@
"ext",
],
- jarjar_rules: ":framework-hidl-jarjar",
+ jarjar_rules: "jarjar_rules_hidl.txt",
static_libs: [
"apex_aidl_interface-java",
@@ -686,18 +687,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",
],
@@ -732,11 +739,6 @@
],
}
-filegroup {
- name: "framework-hidl-jarjar",
- srcs: ["jarjar_rules_hidl.txt"],
-}
-
java_library {
name: "framework",
defaults: ["framework-defaults"],
@@ -761,19 +763,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
@@ -844,6 +833,7 @@
"core/java/android/net/ProxyInfoParcelable.aidl",
"core/java/android/net/RouteInfoParcelable.aidl",
"core/java/android/net/StaticIpConfigurationParcelable.aidl",
+ "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
@@ -854,6 +844,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/Android.mk b/Android.mk
index e405345..65d4d24 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,7 @@
update-api: doc-comment-check-docs
# ==== hiddenapi lists =======================================
+ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
.KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)
$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
PRIVATE_FLAGS_INPUTS := $(PRIVATE_FLAGS_INPUTS) $(SOONG_HIDDENAPI_FLAGS)
@@ -108,6 +109,7 @@
$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS))
$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA))
+endif # UNSAFE_DISABLE_HIDDENAPI_FLAGS
# Include subdirectory makefiles
# ============================================================
diff --git a/api/current.txt b/api/current.txt
index bb7ce7b..d787070 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;
@@ -11197,7 +11200,7 @@
method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
method public abstract android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract int getApplicationEnabledSetting(String);
+ method public abstract int getApplicationEnabledSetting(@NonNull String);
method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
method public abstract android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11205,7 +11208,7 @@
method public abstract android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
method public abstract android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException;
method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
- method public abstract int getComponentEnabledSetting(android.content.ComponentName);
+ method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method public abstract android.graphics.drawable.Drawable getDrawable(String, @DrawableRes int, android.content.pm.ApplicationInfo);
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
@@ -11268,8 +11271,8 @@
method public abstract android.content.pm.ProviderInfo resolveContentProvider(String, int);
method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
method public abstract void setApplicationCategoryHint(@NonNull String, int);
- method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(String, int, int);
- method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
+ method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
+ method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(String, String);
method public abstract void updateInstantAppCookie(@Nullable byte[]);
method public abstract void verifyPendingInstall(int, int);
@@ -27164,7 +27167,7 @@
field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
- field public static final String EXTRA_NETWORK_TYPE = "networkType";
+ field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final String EXTRA_REASON = "reason";
@@ -27850,6 +27853,8 @@
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 setMetered(boolean);
method public android.net.VpnService.Builder setMtu(int);
method public android.net.VpnService.Builder setSession(String);
method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]);
@@ -29086,6 +29091,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 +29104,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...);
@@ -41152,6 +41159,7 @@
method public static String capabilitiesToString(int);
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public int getCallCapabilities();
+ method public int getCallDirection();
method @Nullable public android.telecom.CallIdentification getCallIdentification();
method public int getCallProperties();
method public String getCallerDisplayName();
@@ -41188,6 +41196,9 @@
field public static final int CAPABILITY_SUPPORT_DEFLECT = 16777216; // 0x1000000
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+ field public static final int DIRECTION_INCOMING = 0; // 0x0
+ field public static final int DIRECTION_OUTGOING = 1; // 0x1
+ field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff
field public static final int PROPERTY_CONFERENCE = 1; // 0x1
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -41276,6 +41287,15 @@
method public abstract void onScreenCall(@NonNull android.telecom.Call.Details);
method public final void provideCallIdentification(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallIdentification);
method public final void respondToCall(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallScreeningService.CallResponse);
+ field public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED = "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
+ field public static final int CALL_DURATION_LONG = 4; // 0x4
+ field public static final int CALL_DURATION_MEDIUM = 3; // 0x3
+ field public static final int CALL_DURATION_SHORT = 2; // 0x2
+ field public static final int CALL_DURATION_VERY_SHORT = 1; // 0x1
+ field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
+ field public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
+ field public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
+ field public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
field public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
}
@@ -41854,12 +41874,12 @@
public class TelecomManager {
method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
- method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
- method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
- method @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public String getDefaultDialerPackage();
@@ -41881,6 +41901,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, String);
method @RequiresPermission(anyOf={android.Manifest.permission.CALL_PHONE, android.Manifest.permission.MANAGE_OWN_CALLS}) public void placeCall(android.net.Uri, android.os.Bundle);
method public void registerPhoneAccount(android.telecom.PhoneAccount);
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void reportNuisanceCallStatus(@NonNull android.net.Uri, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
@@ -41955,8 +41976,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();
@@ -42074,7 +42095,7 @@
}
public final class AvailableNetworkInfo implements android.os.Parcelable {
- ctor public AvailableNetworkInfo(int, int, java.util.ArrayList<java.lang.String>);
+ ctor public AvailableNetworkInfo(int, int, java.util.List<java.lang.String>);
method public int describeContents();
method public java.util.List<java.lang.String> getMccMncs();
method public int getPriority();
@@ -42126,7 +42147,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";
@@ -42214,6 +42237,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";
@@ -42875,6 +42901,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();
@@ -42991,6 +43018,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();
@@ -43022,7 +43050,7 @@
method public int getNetworkType();
method public int getPhoneCount();
method public int getPhoneType();
- method public int getPreferredOpportunisticDataSubscription();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.ServiceState getServiceState();
method @Nullable public android.telephony.SignalStrength getSignalStrength();
method public int getSimCarrierId();
@@ -43038,6 +43066,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();
@@ -43057,6 +43086,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
+ method public boolean isRttSupported();
method public boolean isSmsCapable();
method @Deprecated public boolean isTtyModeSupported();
method public boolean isVoiceCapable();
@@ -43080,8 +43110,10 @@
method public boolean setVoiceMailNumber(String, String);
method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
method public boolean updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>);
field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
+ field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
@@ -43119,6 +43151,7 @@
field public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
+ field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY";
field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
field public static final String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID";
@@ -43129,6 +43162,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
@@ -43196,6 +43230,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);
@@ -43351,6 +43397,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);
@@ -43571,9 +43618,9 @@
}
public interface GroupCallCallback {
- method public void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
- method public void onError(int, @Nullable String);
- method public void onGroupCallStateChanged(int, int);
+ method public default void onBroadcastSignalStrengthUpdated(@IntRange(from=0xffffffff, to=4) int);
+ method public default void onError(int, @Nullable String);
+ method public default void onGroupCallStateChanged(int, int);
field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
}
@@ -43631,10 +43678,10 @@
}
public interface MbmsGroupCallSessionCallback {
- method public void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
- method public void onError(int, @Nullable String);
- method public void onMiddlewareReady();
- method public void onServiceInterfaceAvailable(@NonNull String, int);
+ method public default void onAvailableSaisUpdated(@NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.util.List<java.lang.Integer>>);
+ method public default void onError(int, @Nullable String);
+ method public default void onMiddlewareReady();
+ method public default void onServiceInterfaceAvailable(@NonNull String, int);
}
public class MbmsStreamingSessionCallback {
@@ -55506,13 +55553,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;
}
@@ -55683,12 +55730,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);
@@ -56177,8 +56224,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);
@@ -56188,8 +56235,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);
@@ -57015,45 +57062,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();
@@ -57940,8 +57987,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);
@@ -57953,7 +58000,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);
@@ -57968,8 +58015,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);
@@ -58170,7 +58217,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();
@@ -58268,13 +58315,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 {
@@ -58597,8 +58644,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;
@@ -58606,10 +58653,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>);
}
@@ -58644,20 +58691,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();
@@ -58746,7 +58793,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();
@@ -58789,8 +58836,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();
@@ -58803,7 +58850,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();
}
@@ -58811,9 +58858,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;
}
@@ -58827,7 +58874,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();
}
@@ -58839,8 +58886,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();
}
}
@@ -59857,20 +59904,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 {
@@ -59884,7 +59931,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();
@@ -59898,8 +59945,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();
@@ -59918,8 +59965,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);
@@ -59933,8 +59980,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 {
@@ -61767,20 +61814,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);
}
@@ -64387,7 +64434,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);
@@ -64627,7 +64674,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);
@@ -66281,8 +66328,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> {
@@ -66391,161 +66438,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 {
@@ -66629,7 +66676,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);
@@ -66717,8 +66764,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;
}
@@ -66729,7 +66776,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);
@@ -66759,12 +66806,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>);
@@ -67282,7 +67329,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);
@@ -67300,8 +67347,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();
@@ -67495,7 +67542,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);
@@ -68160,7 +68207,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);
@@ -68180,7 +68227,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> {
@@ -68571,7 +68618,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>);
@@ -68599,8 +68646,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 {
@@ -70352,7 +70399,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);
@@ -70365,7 +70412,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);
@@ -70381,7 +70428,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);
@@ -70392,8 +70439,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;
@@ -70655,8 +70702,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 776889a..8a7cf2e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -101,6 +101,7 @@
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
+ field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
@@ -743,14 +744,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
@@ -833,8 +838,10 @@
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
field public static final String BACKUP_SERVICE = "backup";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
+ field public static final String DYNAMIC_ANDROID_SERVICE = "dynamic_android";
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";
@@ -3053,6 +3060,7 @@
public class CaptivePortal implements android.os.Parcelable {
ctor public CaptivePortal(android.os.IBinder);
+ method public void logEvent(int, String);
method public void useNetwork();
field public static final int APP_RETURN_DISMISSED = 0; // 0x0
field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -3060,9 +3068,10 @@
}
public class ConnectivityManager {
- method @RequiresPermission("android.permission.PACKET_KEEPALIVE_OFFLOAD") public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method public boolean getAvoidBadWifi();
method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
+ method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -3073,6 +3082,9 @@
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
field public static final int TETHERING_USB = 1; // 0x1
field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
}
public abstract static class ConnectivityManager.OnStartTetheringCallback {
@@ -3081,9 +3093,21 @@
method public void onTetheringStarted();
}
+ public abstract static class ConnectivityManager.TetheringEntitlementValueListener {
+ ctor public ConnectivityManager.TetheringEntitlementValueListener();
+ method public void onEntitlementResult(int);
+ }
+
+ 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();
@@ -3092,9 +3116,13 @@
public final class LinkProperties implements android.os.Parcelable {
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();
+ method public java.util.List<java.net.InetAddress> getPcscfServers();
method public String getTcpBufferSizes();
method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
method public boolean hasGlobalIPv6Address();
@@ -3105,6 +3133,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);
@@ -3112,6 +3141,8 @@
method public void setInterfaceName(String);
method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
method public void setMtu(int);
+ method public void setNat64Prefix(android.net.IpPrefix);
+ method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(String);
method public void setUsePrivateDns(boolean);
@@ -3119,6 +3150,7 @@
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -3165,7 +3197,12 @@
field public static final String EXTRA_PACKAGE_NAME = "packageName";
}
+ public class NetworkStack {
+ field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
+ }
+
public final class RouteInfo implements android.os.Parcelable {
+ ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
method public int getType();
field public static final int RTN_THROW = 9; // 0x9
field public static final int RTN_UNICAST = 1; // 0x1
@@ -3203,10 +3240,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 {
@@ -3228,6 +3286,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 {
@@ -3299,6 +3400,7 @@
}
public class IpConnectivityLog {
+ ctor public IpConnectivityLog();
method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
@@ -3347,6 +3449,20 @@
field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
}
+ public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ public static class RaEvent.Builder {
+ ctor public RaEvent.Builder();
+ method public android.net.metrics.RaEvent build();
+ method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+ }
+
public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
method public static String getProbeName(int);
field public static final int DNS_FAILURE = 0; // 0x0
@@ -3372,10 +3488,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;
}
}
@@ -3835,6 +3960,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
}
@@ -3851,6 +3977,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";
@@ -4163,6 +4319,7 @@
}
public final class UserHandle implements android.os.Parcelable {
+ method public static int getAppId(int);
method public int getIdentifier();
method @Deprecated public boolean isOwner();
method public boolean isSystem();
@@ -5907,8 +6064,9 @@
}
public class PhoneStateListener {
- method public void onCallAttributesChanged(android.telephony.CallAttributes);
+ method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
method public void onCallDisconnectCauseChanged(int, int);
+ method public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
method public void onRadioPowerStateChanged(int);
@@ -5916,6 +6074,7 @@
method public void onVoiceActivationStateChanged(int);
field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+ field public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
field public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
@@ -6086,7 +6245,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();
}
@@ -6146,7 +6304,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();
@@ -6163,13 +6320,12 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
- method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public int getPreferredNetworkType(int);
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();
@@ -6178,6 +6334,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();
@@ -6194,6 +6351,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);
@@ -6207,6 +6365,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
method public void updateServiceLocation();
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -6214,34 +6373,12 @@
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+ field public static final String EXTRA_DEBUG_EVENT_DESCRIPTION = "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
+ field public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
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
- field public static final int NETWORK_MODE_EVDO_NO_CDMA = 6; // 0x6
- field public static final int NETWORK_MODE_GLOBAL = 7; // 0x7
- field public static final int NETWORK_MODE_GSM_ONLY = 1; // 0x1
- field public static final int NETWORK_MODE_GSM_UMTS = 3; // 0x3
- field public static final int NETWORK_MODE_LTE_CDMA_EVDO = 8; // 0x8
- field public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; // 0xa
- field public static final int NETWORK_MODE_LTE_GSM_WCDMA = 9; // 0x9
- field public static final int NETWORK_MODE_LTE_ONLY = 11; // 0xb
- field public static final int NETWORK_MODE_LTE_TDSCDMA = 15; // 0xf
- field public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; // 0x16
- field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; // 0x11
- field public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; // 0x14
- field public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; // 0x13
- field public static final int NETWORK_MODE_LTE_WCDMA = 12; // 0xc
- field public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; // 0x15
- field public static final int NETWORK_MODE_TDSCDMA_GSM = 16; // 0x10
- field public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; // 0x12
- field public static final int NETWORK_MODE_TDSCDMA_ONLY = 13; // 0xd
- field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
- field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
- field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
field public static final int NETWORK_TYPE_BITMASK_1xRTT = 128; // 0x80
field public static final int NETWORK_TYPE_BITMASK_CDMA = 16; // 0x10
field public static final int NETWORK_TYPE_BITMASK_EDGE = 4; // 0x4
@@ -6292,18 +6429,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();
@@ -6331,7 +6456,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();
@@ -6342,9 +6467,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;
}
@@ -6358,8 +6483,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();
@@ -6585,11 +6710,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);
@@ -6598,7 +6725,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);
@@ -6710,6 +6839,16 @@
field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants;
}
+ public class ImsException extends java.lang.Exception {
+ ctor public ImsException(@Nullable String);
+ ctor public ImsException(@Nullable String, int);
+ ctor public ImsException(@Nullable String, int, Throwable);
+ method public int getCode();
+ field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
+ field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
+ field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
+ }
+
public final class ImsExternalCallState implements android.os.Parcelable {
ctor public ImsExternalCallState(String, android.net.Uri, android.net.Uri, boolean, int, int, boolean);
method public int describeContents();
@@ -6727,7 +6866,7 @@
}
public class ImsMmTelManager {
- method public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(android.content.Context, int);
+ method public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
@@ -6736,8 +6875,8 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSetting(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int);
@@ -7172,13 +7311,21 @@
}
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 @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 public static android.telephony.ims.ProvisioningManager createForSubscriptionId(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) throws android.telephony.ims.ImsException;
+ 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 386beaa..34c8f6e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -600,6 +600,7 @@
public class CaptivePortal implements android.os.Parcelable {
ctor public CaptivePortal(android.os.IBinder);
+ method public void logEvent(int, String);
method public void useNetwork();
field public static final int APP_RETURN_DISMISSED = 0; // 0x0
field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -611,11 +612,20 @@
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
}
+ public final class IpPrefix implements android.os.Parcelable {
+ ctor public IpPrefix(java.net.InetAddress, int);
+ ctor public IpPrefix(String);
+ }
+
public final class IpSecManager {
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
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();
@@ -623,7 +633,11 @@
}
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();
method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
method public boolean hasGlobalIPv6Address();
@@ -634,7 +648,10 @@
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>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(String);
method public void setUsePrivateDns(boolean);
@@ -642,6 +659,7 @@
}
public class Network implements android.os.Parcelable {
+ ctor public Network(android.net.Network);
method public android.net.Network getPrivateDnsBypassingCopy();
}
@@ -651,18 +669,87 @@
method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
}
+ public class NetworkStack {
+ field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
+ }
+
public final class RouteInfo implements android.os.Parcelable {
+ ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
method public int getType();
field public static final int RTN_THROW = 9; // 0x9
field public static final int RTN_UNICAST = 1; // 0x1
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);
}
}
@@ -738,6 +825,7 @@
}
public class IpConnectivityLog {
+ ctor public IpConnectivityLog();
method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
@@ -786,6 +874,20 @@
field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
}
+ public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+ }
+
+ public static class RaEvent.Builder {
+ ctor public RaEvent.Builder();
+ method public android.net.metrics.RaEvent build();
+ method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+ method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+ }
+
public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
method public static String getProbeName(int);
field public static final int DNS_FAILURE = 0; // 0x0
@@ -808,6 +910,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 {
@@ -1355,7 +1477,6 @@
public class TelephonyManager {
method public int getCarrierIdListVersion();
- method public boolean isRttSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
method public void setCarrierTestOverride(String, String, String, String, String, String, String);
field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
@@ -1673,6 +1794,10 @@
method public boolean isSystemGroup();
}
+ public abstract class LayoutInflater {
+ method public void setPrecompiledLayoutsEnabledForTesting(boolean);
+ }
+
public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable {
method public void setActionButton(int);
method public void setButtonState(int);
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index 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..a8fc9d24 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;
@@ -113,11 +114,13 @@
import android.os.Build;
import android.os.DeviceIdleManager;
import android.os.DropBoxManager;
+import android.os.DynamicAndroidManager;
import android.os.HardwarePropertiesManager;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.IDumpstate;
+import android.os.IDynamicAndroidService;
import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
@@ -288,6 +291,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
@@ -1056,6 +1067,16 @@
throws ServiceNotFoundException {
return new TimeZoneDetector();
}});
+ registerService(Context.DYNAMIC_ANDROID_SERVICE, DynamicAndroidManager.class,
+ new CachedServiceFetcher<DynamicAndroidManager>() {
+ @Override
+ public DynamicAndroidManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.DYNAMIC_ANDROID_SERVICE);
+ return new DynamicAndroidManager(
+ IDynamicAndroidService.Stub.asInterface(b));
+ }});
}
/**
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..ba6e7ae8 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)
@@ -4294,6 +4304,14 @@
*/
public static final String TELEPHONY_RCS_SERVICE = "ircs";
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.os.DynamicAndroidManager}.
+ * @hide
+ */
+ @SystemApi
+ public static final String DYNAMIC_ANDROID_SERVICE = "dynamic_android";
+
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
index 81e4105..7790067 100644
--- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
+++ b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java
@@ -25,12 +25,6 @@
* Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is
* included by default.
*
- * <p>This is separated out so that it can be conditionally included at build time depending on
- * whether org.apache.http.legacy is on the bootclasspath or not. In order to include this at
- * build time, and remove org.apache.http.legacy from the bootclasspath pass
- * REMOVE_OAHL_FROM_BCP=true on the build command line, otherwise this class will not be included
- * and the
- *
* @hide
*/
@VisibleForTesting
diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java
index 03eefed..b19196a 100644
--- a/core/java/android/content/pm/PackageBackwardCompatibility.java
+++ b/core/java/android/content/pm/PackageBackwardCompatibility.java
@@ -45,13 +45,9 @@
static {
final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
- // Attempt to load and add the optional updater that will only be available when
- // REMOVE_OAHL_FROM_BCP=true. If that could not be found then add the default updater that
- // will remove any references to org.apache.http.library from the package so that it does
- // not try and load the library when it is on the bootclasspath.
- boolean bootClassPathContainsOAHL = !addOptionalUpdater(packageUpdaters,
- "android.content.pm.OrgApacheHttpLegacyUpdater",
- RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);
+ // Automatically add the org.apache.http.legacy library to the app classpath if the app
+ // targets < P.
+ packageUpdaters.add(new OrgApacheHttpLegacyUpdater());
packageUpdaters.add(new AndroidHidlUpdater());
@@ -70,7 +66,7 @@
PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
.toArray(new PackageSharedLibraryUpdater[0]);
INSTANCE = new PackageBackwardCompatibility(
- bootClassPathContainsOAHL, bootClassPathContainsATB, updaterArray);
+ bootClassPathContainsATB, updaterArray);
}
/**
@@ -116,15 +112,12 @@
return INSTANCE;
}
- private final boolean mBootClassPathContainsOAHL;
-
private final boolean mBootClassPathContainsATB;
private final PackageSharedLibraryUpdater[] mPackageUpdaters;
- public PackageBackwardCompatibility(boolean bootClassPathContainsOAHL,
+ public PackageBackwardCompatibility(
boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
- this.mBootClassPathContainsOAHL = bootClassPathContainsOAHL;
this.mBootClassPathContainsATB = bootClassPathContainsATB;
this.mPackageUpdaters = packageUpdaters;
}
@@ -148,14 +141,6 @@
}
/**
- * True if the org.apache.http.legacy is on the bootclasspath, false otherwise.
- */
- @VisibleForTesting
- public static boolean bootClassPathContainsOAHL() {
- return INSTANCE.mBootClassPathContainsOAHL;
- }
-
- /**
* True if the android.test.base is on the bootclasspath, false otherwise.
*/
@VisibleForTesting
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2130c39..92c757c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5501,7 +5501,7 @@
* @param newState The new enabled state for the component.
* @param flags Optional behavior flags.
*/
- public abstract void setComponentEnabledSetting(ComponentName componentName,
+ public abstract void setComponentEnabledSetting(@NonNull ComponentName componentName,
@EnabledState int newState, @EnabledFlags int flags);
/**
@@ -5515,7 +5515,7 @@
* @return Returns the current enabled state for the component.
*/
public abstract @EnabledState int getComponentEnabledSetting(
- ComponentName componentName);
+ @NonNull ComponentName componentName);
/**
* Set the enabled setting for an application
@@ -5528,7 +5528,7 @@
* @param newState The new enabled state for the application.
* @param flags Optional behavior flags.
*/
- public abstract void setApplicationEnabledSetting(String packageName,
+ public abstract void setApplicationEnabledSetting(@NonNull String packageName,
@EnabledState int newState, @EnabledFlags int flags);
/**
@@ -5542,7 +5542,7 @@
* @return Returns the current enabled state for the application.
* @throws IllegalArgumentException if the named package does not exist.
*/
- public abstract @EnabledState int getApplicationEnabledSetting(String packageName);
+ public abstract @EnabledState int getApplicationEnabledSetting(@NonNull String packageName);
/**
* Flush the package restrictions for a given user to disk. This forces the package restrictions
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index b2288fc..87568e8 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -16,13 +16,15 @@
package android.ddm;
+import android.os.Debug;
+import android.os.UserHandle;
+import android.util.Log;
+
+import dalvik.system.VMRuntime;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
-import android.os.Debug;
-import android.os.UserHandle;
-import dalvik.system.VMRuntime;
import java.nio.ByteBuffer;
@@ -35,6 +37,8 @@
public static final int CHUNK_WAIT = type("WAIT");
public static final int CHUNK_FEAT = type("FEAT");
+ private static final int CLIENT_PROTOCOL_VERSION = 1;
+
private static DdmHandleHello mInstance = new DdmHandleHello();
private static final String[] FRAMEWORK_FEATURES = new String[] {
@@ -145,7 +149,7 @@
+ vmFlags.length() * 2
+ 1);
out.order(ChunkHandler.CHUNK_ORDER);
- out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
+ out.putInt(CLIENT_PROTOCOL_VERSION);
out.putInt(android.os.Process.myPid());
out.putInt(vmIdent.length());
out.putInt(appName.length());
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index 3b01266..3ab35e1 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -117,4 +117,17 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * Log a captive portal login event.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public void logEvent(int eventId, String packageName) {
+ try {
+ ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5bb24ba..fad5318 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -177,10 +177,10 @@
* The lookup key for a {@link NetworkInfo} object. Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
*
- * @deprecated Since {@link NetworkInfo} can vary based on UID, applications
- * should always obtain network information through
- * {@link #getActiveNetworkInfo()}.
- * @see #EXTRA_NETWORK_TYPE
+ * @deprecated The {@link NetworkInfo} object is deprecated, as many of its properties
+ * can't accurately represent modern network characteristics.
+ * Please obtain information about networks from the {@link NetworkCapabilities}
+ * or {@link LinkProperties} objects instead.
*/
@Deprecated
public static final String EXTRA_NETWORK_INFO = "networkInfo";
@@ -189,7 +189,11 @@
* Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast.
*
* @see android.content.Intent#getIntExtra(String, int)
+ * @deprecated The network type is not rich enough to represent the characteristics
+ * of modern networks. Please use {@link NetworkCapabilities} instead,
+ * in particular the transports.
*/
+ @Deprecated
public static final String EXTRA_NETWORK_TYPE = "networkType";
/**
@@ -1014,20 +1018,26 @@
* to remove an existing always-on VPN configuration.
* @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
* {@code false} otherwise.
+ * @param lockdownWhitelist The list of packages that are allowed to access network directly
+ * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+ * this method must be called when a package that should be whitelisted is installed or
+ * uninstalled.
* @return {@code true} if the package is set as always-on VPN controller;
* {@code false} otherwise.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
- boolean lockdownEnabled) {
+ boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
try {
- return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled);
+ return mService.setAlwaysOnVpnPackage(
+ userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- /**
+ /**
* Returns the package name of the currently set always-on VPN application.
* If there is no always-on VPN set, or the VPN is provided by the system instead
* of by an app, {@code null} will be returned.
@@ -1036,6 +1046,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 +1056,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.
@@ -1206,9 +1247,13 @@
* is no current default network.
*
* {@hide}
+ * @deprecated please use {@link #getLinkProperties(Network)} on the return
+ * value of {@link #getActiveNetwork()} instead. In particular,
+ * this method will return non-null LinkProperties even if the
+ * app is blocked by policy from using this network.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 109783091)
public LinkProperties getActiveLinkProperties() {
try {
return mService.getActiveLinkProperties();
@@ -1779,7 +1824,7 @@
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+ case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
int error = message.arg2;
try {
if (error == SUCCESS) {
@@ -2544,6 +2589,7 @@
}
/** {@hide} */
+ @SystemApi
public static final int TETHER_ERROR_NO_ERROR = 0;
/** {@hide} */
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
@@ -2566,9 +2612,13 @@
/** {@hide} */
public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
/** {@hide} */
+ @SystemApi
public static final int TETHER_ERROR_PROVISION_FAILED = 11;
/** {@hide} */
public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
+ /** {@hide} */
+ @SystemApi
+ public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
/**
* Get a more detailed error code after a Tethering or Untethering
@@ -2591,6 +2641,65 @@
}
/**
+ * Callback for use with {@link #getLatestTetheringEntitlementValue} to find out whether
+ * entitlement succeeded.
+ * @hide
+ */
+ @SystemApi
+ public abstract static class TetheringEntitlementValueListener {
+ /**
+ * Called to notify entitlement result.
+ *
+ * @param resultCode a int value of entitlement result. It may be one of
+ * {@link #TETHER_ERROR_NO_ERROR},
+ * {@link #TETHER_ERROR_PROVISION_FAILED}, or
+ * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
+ */
+ public void onEntitlementResult(int resultCode) {}
+ }
+
+ /**
+ * Get the last value of the entitlement check on this downstream. If the cached value is
+ * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
+ * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
+ * guaranteed that the UI-based entitlement check will complete in any specific time period
+ * and may in fact never complete. Any successful entitlement check the platform performs for
+ * any reason will update the cached value.
+ *
+ * @param type the downstream type of tethering. Must be one of
+ * {@link #TETHERING_WIFI},
+ * {@link #TETHERING_USB}, or
+ * {@link #TETHERING_BLUETOOTH}.
+ * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
+ * @param listener an {@link TetheringEntitlementValueListener} which will be called to notify
+ * the caller of the result of entitlement check. The listener may be called zero or
+ * one time.
+ * @param handler {@link Handler} to specify the thread upon which the listener will be invoked.
+ * {@hide}
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi,
+ @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) {
+ Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null.");
+ ResultReceiver wrappedListener = new ResultReceiver(handler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ listener.onEntitlementResult(resultCode);
+ }
+ };
+
+ try {
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName);
+ mService.getLatestTetheringEntitlementValue(type, wrappedListener,
+ showEntitlementUi, pkgName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Report network connectivity status. This is currently used only
* to alter status bar UI.
* <p>This method requires the caller to hold the permission
@@ -3905,10 +4014,17 @@
@Deprecated
public static boolean setProcessDefaultNetwork(@Nullable Network network) {
int netId = (network == null) ? NETID_UNSET : network.netId;
- if (netId == NetworkUtils.getBoundNetworkForProcess()) {
- return true;
+ boolean isSameNetId = (netId == NetworkUtils.getBoundNetworkForProcess());
+
+ if (netId != NETID_UNSET) {
+ netId = network.getNetIdForResolv();
}
- if (NetworkUtils.bindProcessToNetwork(netId)) {
+
+ if (!NetworkUtils.bindProcessToNetwork(netId)) {
+ return false;
+ }
+
+ if (!isSameNetId) {
// Set HTTP proxy system properties to match network.
// TODO: Deprecate this static method and replace it with a non-static version.
try {
@@ -3922,10 +4038,9 @@
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
- return true;
- } else {
- return false;
}
+
+ return true;
}
/**
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/ICaptivePortal.aidl b/core/java/android/net/ICaptivePortal.aidl
index 56ae57d..707b4f6 100644
--- a/core/java/android/net/ICaptivePortal.aidl
+++ b/core/java/android/net/ICaptivePortal.aidl
@@ -22,4 +22,5 @@
*/
oneway interface ICaptivePortal {
void appResponse(int response);
+ void logEvent(int eventId, String packageName);
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e97060a..78fafeb 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);
@@ -194,4 +197,7 @@
int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
boolean isCallerCurrentAlwaysOnVpnApp();
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
+
+ void getLatestTetheringEntitlementValue(int type, in ResultReceiver receiver,
+ boolean showEntitlementUi, String callerPkg);
}
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl
index 0bc2575..a8682f9 100644
--- a/core/java/android/net/INetworkMonitorCallbacks.aidl
+++ b/core/java/android/net/INetworkMonitorCallbacks.aidl
@@ -26,4 +26,5 @@
void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config);
void showProvisioningNotification(String action);
void hideProvisioningNotification();
+ void logCaptivePortalLoginEvent(int eventId, String packageName);
}
\ No newline at end of file
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index 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 4631c56..175263f 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
@@ -83,6 +85,8 @@
* @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
* @hide
*/
+ @SystemApi
+ @TestApi
public IpPrefix(InetAddress address, int prefixLength) {
// We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
// which is unnecessary because getAddress() already returns a clone.
@@ -100,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/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 7436ad0..18726f7 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -16,22 +16,20 @@
package android.net;
-import static android.net.ConnectivityManager.PacketKeepalive.*;
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
+import android.net.SocketKeepalive.InvalidPacketException;
import android.net.util.IpUtils;
import android.os.Parcel;
import android.os.Parcelable;
-import android.system.OsConstants;
import android.util.Log;
-import java.net.Inet4Address;
import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
/**
* Represents the actual packets that are sent by the
- * {@link android.net.ConnectivityManager.PacketKeepalive} API.
+ * {@link android.net.SocketKeepalive} API.
*
* @hide
*/
@@ -53,8 +51,8 @@
/** Packet data. A raw byte string of packet data, not including the link-layer header. */
private final byte[] mPacket;
- private static final int IPV4_HEADER_LENGTH = 20;
- private static final int UDP_HEADER_LENGTH = 8;
+ protected static final int IPV4_HEADER_LENGTH = 20;
+ protected static final int UDP_HEADER_LENGTH = 8;
// This should only be constructed via static factory methods, such as
// nattKeepalivePacket
@@ -80,53 +78,10 @@
}
}
- public static class InvalidPacketException extends Exception {
- public final int error;
- public InvalidPacketException(int error) {
- this.error = error;
- }
- }
-
public byte[] getPacket() {
return mPacket.clone();
}
- public static KeepalivePacketData nattKeepalivePacket(
- InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
- throws InvalidPacketException {
-
- if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
- throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
- }
-
- if (dstPort != NATT_PORT) {
- throw new InvalidPacketException(ERROR_INVALID_PORT);
- }
-
- int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
- ByteBuffer buf = ByteBuffer.allocate(length);
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.putShort((short) 0x4500); // IP version and TOS
- buf.putShort((short) length);
- buf.putInt(0); // ID, flags, offset
- buf.put((byte) 64); // TTL
- buf.put((byte) OsConstants.IPPROTO_UDP);
- int ipChecksumOffset = buf.position();
- buf.putShort((short) 0); // IP checksum
- buf.put(srcAddress.getAddress());
- buf.put(dstAddress.getAddress());
- buf.putShort((short) srcPort);
- buf.putShort((short) dstPort);
- buf.putShort((short) (length - 20)); // UDP length
- int udpChecksumOffset = buf.position();
- buf.putShort((short) 0); // UDP checksum
- buf.put((byte) 0xff); // NAT-T keepalive
- buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
- buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
-
- return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
- }
-
/* Parcelable Implementation */
public int describeContents() {
return 0;
@@ -141,7 +96,7 @@
out.writeByteArray(mPacket);
}
- private KeepalivePacketData(Parcel in) {
+ protected KeepalivePacketData(Parcel in) {
srcAddress = NetworkUtils.numericToInetAddress(in.readString());
dstAddress = NetworkUtils.numericToInetAddress(in.readString());
srcPort = in.readInt();
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index a536d08..8d779aa 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -162,6 +162,8 @@
* {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
* @hide
*/
+ @SystemApi
+ @TestApi
public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
init(address, prefixLength, flags, scope);
}
@@ -174,6 +176,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(InetAddress address, int prefixLength) {
this(address, prefixLength, 0, 0);
this.scope = scopeForUnicastAddress(address);
@@ -197,6 +200,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public LinkAddress(String address) {
this(address, 0, 0);
this.scope = scopeForUnicastAddress(this.address);
@@ -210,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 21b6a8e..42db0fd 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -174,7 +174,8 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @TestApi
public LinkProperties(LinkProperties source) {
if (source != null) {
mIfaceName = source.mIfaceName;
@@ -286,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;
@@ -314,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) {
@@ -576,6 +580,8 @@
* @param addresses The {@link Collection} of PCSCF servers to set in this object.
* @hide
*/
+ @SystemApi
+ @TestApi
public void setPcscfServers(Collection<InetAddress> pcscfServers) {
mPcscfs.clear();
for (InetAddress pcscfServer: pcscfServers) {
@@ -590,6 +596,8 @@
* this link.
* @hide
*/
+ @SystemApi
+ @TestApi
public List<InetAddress> getPcscfServers() {
return Collections.unmodifiableList(mPcscfs);
}
@@ -781,6 +789,8 @@
* @return the NAT64 prefix.
* @hide
*/
+ @SystemApi
+ @TestApi
public @Nullable IpPrefix getNat64Prefix() {
return mNat64Prefix;
}
@@ -794,6 +804,8 @@
* @param prefix the NAT64 prefix.
* @hide
*/
+ @SystemApi
+ @TestApi
public void setNat64Prefix(IpPrefix prefix) {
if (prefix != null && prefix.getPrefixLength() != 96) {
throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
new file mode 100644
index 0000000..bdb246f
--- /dev/null
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
+
+import android.net.SocketKeepalive.InvalidPacketException;
+import android.net.util.IpUtils;
+import android.system.OsConstants;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/** @hide */
+public final class NattKeepalivePacketData extends KeepalivePacketData {
+
+ // This should only be constructed via static factory methods, such as
+ // nattKeepalivePacket
+ private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
+ InetAddress dstAddress, int dstPort, byte[] data) throws
+ InvalidPacketException {
+ super(srcAddress, srcPort, dstAddress, dstPort, data);
+ }
+
+ /**
+ * Factory method to create Nat-T keepalive packet structure.
+ */
+ public static NattKeepalivePacketData nattKeepalivePacket(
+ InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
+ throws InvalidPacketException {
+
+ if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+ }
+
+ if (dstPort != NattSocketKeepalive.NATT_PORT) {
+ throw new InvalidPacketException(ERROR_INVALID_PORT);
+ }
+
+ int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
+ ByteBuffer buf = ByteBuffer.allocate(length);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.putShort((short) 0x4500); // IP version and TOS
+ buf.putShort((short) length);
+ buf.putInt(0); // ID, flags, offset
+ buf.put((byte) 64); // TTL
+ buf.put((byte) OsConstants.IPPROTO_UDP);
+ int ipChecksumOffset = buf.position();
+ buf.putShort((short) 0); // IP checksum
+ buf.put(srcAddress.getAddress());
+ buf.put(dstAddress.getAddress());
+ buf.putShort((short) srcPort);
+ buf.putShort((short) dstPort);
+ buf.putShort((short) (length - 20)); // UDP length
+ int udpChecksumOffset = buf.position();
+ buf.putShort((short) 0); // UDP checksum
+ buf.put((byte) 0xff); // NAT-T keepalive
+ buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
+ buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
+
+ return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
+ }
+}
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/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 99bfc14..dfb6d6f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -18,7 +18,6 @@
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.net.ConnectivityManager.PacketKeepalive;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -154,7 +153,7 @@
*
* Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
*/
- public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
+ public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
/**
* Requests that the specified keepalive packet be stopped.
@@ -163,20 +162,20 @@
*
* Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
*/
- public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
+ public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12;
/**
- * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive
- * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous
+ * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive
+ * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous
* error notification.
*
- * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to
- * so that the app's PacketKeepaliveCallback methods can be called.
+ * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive},
+ * so that the app's {@link SocketKeepalive.Callback} methods can be called.
*
* arg1 = slot number of the keepalive
* arg2 = error code
*/
- public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
+ public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
/**
* Sent by ConnectivityService to inform this network transport of signal strength thresholds
@@ -288,12 +287,12 @@
saveAcceptUnvalidated(msg.arg1 != 0);
break;
}
- case CMD_START_PACKET_KEEPALIVE: {
- startPacketKeepalive(msg);
+ case CMD_START_SOCKET_KEEPALIVE: {
+ startSocketKeepalive(msg);
break;
}
- case CMD_STOP_PACKET_KEEPALIVE: {
- stopPacketKeepalive(msg);
+ case CMD_STOP_SOCKET_KEEPALIVE: {
+ stopSocketKeepalive(msg);
break;
}
@@ -443,22 +442,22 @@
/**
* Requests that the network hardware send the specified packet at the specified interval.
*/
- protected void startPacketKeepalive(Message msg) {
- onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+ protected void startSocketKeepalive(Message msg) {
+ onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
}
/**
- * Requests that the network hardware send the specified packet at the specified interval.
+ * Requests that the network hardware stops sending keepalive packets.
*/
- protected void stopPacketKeepalive(Message msg) {
- onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+ protected void stopSocketKeepalive(Message msg) {
+ onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
}
/**
- * Called by the network when a packet keepalive event occurs.
+ * Called by the network when a socket keepalive event occurs.
*/
- public void onPacketKeepaliveEvent(int slot, int reason) {
- queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason);
+ public void onSocketKeepaliveEvent(int slot, int reason) {
+ queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, reason);
}
/**
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index d277034..b6cd635 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -20,7 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -46,9 +48,22 @@
* @hide
*/
@SystemService(Context.NETWORK_STACK_SERVICE)
+@SystemApi
+@TestApi
public class NetworkStack {
private static final String TAG = NetworkStack.class.getSimpleName();
+ /**
+ * Permission granted only to the NetworkStack APK, defined in NetworkStackStub with signature
+ * protection level.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final String PERMISSION_MAINLINE_NETWORK_STACK =
+ "android.permission.MAINLINE_NETWORK_STACK";
+
+ /** @hide */
public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
@@ -66,12 +81,14 @@
void onNetworkStackConnected(INetworkStackConnector connector);
}
+ /** @hide */
public NetworkStack() { }
/**
* Create a DHCP server according to the specified parameters.
*
* <p>The server will be returned asynchronously through the provided callbacks.
+ * @hide
*/
public void makeDhcpServer(final String ifName, final DhcpServingParamsParcel params,
final IDhcpServerCallbacks cb) {
@@ -88,6 +105,7 @@
* Create an IpClient on the specified interface.
*
* <p>The IpClient will be returned asynchronously through the provided callbacks.
+ * @hide
*/
public void makeIpClient(String ifName, IIpClientCallbacks cb) {
requestConnector(connector -> {
@@ -103,11 +121,13 @@
* Create a NetworkMonitor.
*
* <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
+ * @hide
*/
- 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();
}
@@ -152,6 +172,7 @@
* the system server on devices that do not support the network stack module. The network stack
* connector will then be delivered asynchronously to clients that requested it before it was
* started.
+ * @hide
*/
public void start(Context context) {
mNetworkStackStartRequested = true;
@@ -222,7 +243,7 @@
private void requestConnector(@NonNull NetworkStackCallback request) {
// TODO: PID check.
final int caller = Binder.getCallingUid();
- if (caller != Process.SYSTEM_UID && caller != Process.BLUETOOTH_UID) {
+ if (caller != Process.SYSTEM_UID && !UserHandle.isSameApp(caller, Process.BLUETOOTH_UID)) {
// Don't even attempt to obtain the connector and give a nice error message
throw new SecurityException(
"Only the system server should try to bind to the network stack.");
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 7f4d8cd1..0ae29b1 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.
*
@@ -72,6 +71,18 @@
throws SocketException;
/**
+ * Attaches a socket filter that drops all of incoming packets.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException;
+
+ /**
+ * Detaches a socket filter.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void detachBPFFilter(FileDescriptor fd) throws SocketException;
+
+ /**
* Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
* @param fd the socket's {@link FileDescriptor}.
* @param ifIndex the interface index.
@@ -171,120 +182,48 @@
private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
FileDescriptor fd) throws IOException;
+
/**
- * @see #intToInet4AddressHTL(int)
- * @deprecated Use either {@link #intToInet4AddressHTH(int)}
- * or {@link #intToInet4AddressHTL(int)}
+ * Get the tcp repair window associated with the {@code fd}.
+ *
+ * @param fd the tcp socket's {@link FileDescriptor}.
+ * @return a {@link TcpRepairWindow} object indicates tcp window size.
+ */
+ public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd)
+ throws ErrnoException;
+
+ /**
+ * @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 +241,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 +268,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 +312,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 +341,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/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 6bf2c67..5c0f758 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -110,6 +110,8 @@
*
* @hide
*/
+ @SystemApi
+ @TestApi
public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) {
switch (type) {
case RTN_UNICAST:
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 97d50f4..7ea1bef 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -109,6 +109,46 @@
**/
public static final int MAX_INTERVAL_SEC = 3600;
+ /**
+ * An exception that embarks an error code.
+ * @hide
+ */
+ public static class ErrorCodeException extends Exception {
+ public final int error;
+ public ErrorCodeException(final int error, final Throwable e) {
+ super(e);
+ this.error = error;
+ }
+ public ErrorCodeException(final int error) {
+ this.error = error;
+ }
+ }
+
+ /**
+ * This socket is invalid.
+ * See the error code for details, and the optional cause.
+ * @hide
+ */
+ public static class InvalidSocketException extends ErrorCodeException {
+ public InvalidSocketException(final int error, final Throwable e) {
+ super(error, e);
+ }
+ public InvalidSocketException(final int error) {
+ super(error);
+ }
+ }
+
+ /**
+ * This packet is invalid.
+ * See the error code for details.
+ * @hide
+ */
+ public static class InvalidPacketException extends ErrorCodeException {
+ public InvalidPacketException(final int error) {
+ super(error);
+ }
+ }
+
@NonNull final IConnectivityManager mService;
@NonNull final Network mNetwork;
@NonNull private final Executor mExecutor;
@@ -135,7 +175,7 @@
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case NetworkAgent.EVENT_PACKET_KEEPALIVE:
+ case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
final int status = message.arg2;
try {
if (status == SUCCESS) {
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/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java
new file mode 100644
index 0000000..f07dfb6
--- /dev/null
+++ b/core/java/android/net/TcpKeepalivePacketData.java
@@ -0,0 +1,234 @@
+/*
+ * 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;
+
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.SocketKeepalive.InvalidPacketException;
+import android.net.util.IpUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.system.OsConstants;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Objects;
+
+/**
+ * Represents the actual tcp keep alive packets which will be used for hardware offload.
+ * @hide
+ */
+public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
+ private static final String TAG = "TcpKeepalivePacketData";
+
+ /** TCP sequence number. */
+ public final int tcpSeq;
+
+ /** TCP ACK number. */
+ public final int tcpAck;
+
+ /** TCP RCV window. */
+ public final int tcpWnd;
+
+ /** TCP RCV window scale. */
+ public final int tcpWndScale;
+
+ private static final int IPV4_HEADER_LENGTH = 20;
+ private static final int IPV6_HEADER_LENGTH = 40;
+ private static final int TCP_HEADER_LENGTH = 20;
+
+ // This should only be constructed via static factory methods, such as
+ // tcpKeepalivePacket.
+ private TcpKeepalivePacketData(TcpSocketInfo tcpDetails, byte[] data)
+ throws InvalidPacketException {
+ super(tcpDetails.srcAddress, tcpDetails.srcPort, tcpDetails.dstAddress,
+ tcpDetails.dstPort, data);
+ tcpSeq = tcpDetails.seq;
+ tcpAck = tcpDetails.ack;
+ // In the packet, the window is shifted right by the window scale.
+ tcpWnd = tcpDetails.rcvWnd;
+ tcpWndScale = tcpDetails.rcvWndScale;
+ }
+
+ /**
+ * Factory method to create tcp keepalive packet structure.
+ */
+ public static TcpKeepalivePacketData tcpKeepalivePacket(
+ TcpSocketInfo tcpDetails) throws InvalidPacketException {
+ final byte[] packet;
+ if ((tcpDetails.srcAddress instanceof Inet4Address)
+ && (tcpDetails.dstAddress instanceof Inet4Address)) {
+ packet = buildV4Packet(tcpDetails);
+ } else {
+ // TODO: support ipv6
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+ }
+
+ return new TcpKeepalivePacketData(tcpDetails, packet);
+ }
+
+ /**
+ * Build ipv4 tcp keepalive packet, not including the link-layer header.
+ */
+ // TODO : if this code is ever moved to the network stack, factorize constants with the ones
+ // over there.
+ private static byte[] buildV4Packet(TcpSocketInfo tcpDetails) {
+ final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
+ ByteBuffer buf = ByteBuffer.allocate(length);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ // IP version and TOS. TODO : fetch this from getsockopt(SOL_IP, IP_TOS)
+ buf.putShort((short) 0x4500);
+ buf.putShort((short) length);
+ buf.putInt(0x4000); // ID, flags=DF, offset
+ // TODO : fetch TTL from getsockopt(SOL_IP, IP_TTL)
+ buf.put((byte) 64);
+ buf.put((byte) OsConstants.IPPROTO_TCP);
+ final int ipChecksumOffset = buf.position();
+ buf.putShort((short) 0); // IP checksum
+ buf.put(tcpDetails.srcAddress.getAddress());
+ buf.put(tcpDetails.dstAddress.getAddress());
+ buf.putShort((short) tcpDetails.srcPort);
+ buf.putShort((short) tcpDetails.dstPort);
+ buf.putInt(tcpDetails.seq); // Sequence Number
+ buf.putInt(tcpDetails.ack); // ACK
+ buf.putShort((short) 0x5010); // TCP length=5, flags=ACK
+ buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size
+ final int tcpChecksumOffset = buf.position();
+ buf.putShort((short) 0); // TCP checksum
+ // URG is not set therefore the urgent pointer is not included
+ buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
+ buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum(
+ buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH));
+
+ return buf.array();
+ }
+
+ // TODO: add buildV6Packet.
+
+ /** Represents tcp/ip information. */
+ // TODO: Replace TcpSocketInfo with TcpKeepalivePacketDataParcelable.
+ public static class TcpSocketInfo {
+ public final InetAddress srcAddress;
+ public final InetAddress dstAddress;
+ public final int srcPort;
+ public final int dstPort;
+ public final int seq;
+ public final int ack;
+ public final int rcvWnd;
+ public final int rcvWndScale;
+
+ public TcpSocketInfo(InetAddress sAddr, int sPort, InetAddress dAddr,
+ int dPort, int writeSeq, int readSeq, int rWnd, int rWndScale) {
+ srcAddress = sAddr;
+ dstAddress = dAddr;
+ srcPort = sPort;
+ dstPort = dPort;
+ seq = writeSeq;
+ ack = readSeq;
+ rcvWnd = rWnd;
+ rcvWndScale = rWndScale;
+ }
+ }
+
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof TcpKeepalivePacketData)) return false;
+ final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
+ return this.srcAddress.equals(other.srcAddress)
+ && this.dstAddress.equals(other.dstAddress)
+ && this.srcPort == other.srcPort
+ && this.dstPort == other.dstPort
+ && this.tcpAck == other.tcpAck
+ && this.tcpSeq == other.tcpSeq
+ && this.tcpWnd == other.tcpWnd
+ && this.tcpWndScale == other.tcpWndScale;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(srcAddress, dstAddress, srcPort, dstPort, tcpAck, tcpSeq, tcpWnd,
+ tcpWndScale);
+ }
+
+ /* Parcelable Implementation. */
+ /* Note that this object implements parcelable (and needs to keep doing this as it inherits
+ * from a class that does), but should usually be parceled as a stable parcelable using
+ * the toStableParcelable() and fromStableParcelable() methods.
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel. */
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(tcpSeq);
+ out.writeInt(tcpAck);
+ out.writeInt(tcpWnd);
+ out.writeInt(tcpWndScale);
+ }
+
+ private TcpKeepalivePacketData(Parcel in) {
+ super(in);
+ tcpSeq = in.readInt();
+ tcpAck = in.readInt();
+ tcpWnd = in.readInt();
+ tcpWndScale = in.readInt();
+ }
+
+ /** Parcelable Creator. */
+ public static final Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ new Parcelable.Creator<TcpKeepalivePacketData>() {
+ public TcpKeepalivePacketData createFromParcel(Parcel in) {
+ return new TcpKeepalivePacketData(in);
+ }
+
+ public TcpKeepalivePacketData[] newArray(int size) {
+ return new TcpKeepalivePacketData[size];
+ }
+ };
+
+ /**
+ * Convert this TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable.
+ */
+ @NonNull
+ public TcpKeepalivePacketDataParcelable toStableParcelable() {
+ final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
+ parcel.srcAddress = srcAddress.getAddress();
+ parcel.srcPort = srcPort;
+ parcel.dstAddress = dstAddress.getAddress();
+ parcel.dstPort = dstPort;
+ parcel.seq = tcpSeq;
+ parcel.ack = tcpAck;
+ return parcel;
+ }
+
+ @Override
+ public String toString() {
+ return "saddr: " + srcAddress
+ + " daddr: " + dstAddress
+ + " sport: " + srcPort
+ + " dport: " + dstPort
+ + " seq: " + tcpSeq
+ + " ack: " + tcpAck
+ + " wnd: " + tcpWnd
+ + " wndScale: " + tcpWndScale;
+ }
+}
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
similarity index 61%
copy from services/net/java/android/net/dhcp/DhcpClient.java
copy to core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
index cddb91f..7329c63 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.net.dhcp;
+package android.net;
-/**
- * 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;
+parcelable TcpKeepalivePacketDataParcelable {
+ byte[] srcAddress;
+ int srcPort;
+ byte[] dstAddress;
+ int dstPort;
+ int seq;
+ int ack;
}
diff --git a/core/java/android/net/TcpRepairWindow.java b/core/java/android/net/TcpRepairWindow.java
new file mode 100644
index 0000000..86034f0
--- /dev/null
+++ b/core/java/android/net/TcpRepairWindow.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * Corresponds to C's {@code struct tcp_repair_window} from
+ * include/uapi/linux/tcp.h
+ *
+ * @hide
+ */
+public final class TcpRepairWindow {
+ public final int sndWl1;
+ public final int sndWnd;
+ public final int maxWindow;
+ public final int rcvWnd;
+ public final int rcvWup;
+ public final int rcvWndScale;
+
+ /**
+ * Constructs an instance with the given field values.
+ */
+ public TcpRepairWindow(final int sndWl1, final int sndWnd, final int maxWindow,
+ final int rcvWnd, final int rcvWup, final int rcvWndScale) {
+ this.sndWl1 = sndWl1;
+ this.sndWnd = sndWnd;
+ this.maxWindow = maxWindow;
+ this.rcvWnd = rcvWnd;
+ this.rcvWup = rcvWup;
+ this.rcvWndScale = rcvWndScale;
+ }
+}
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..784f233 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}.
@@ -782,6 +791,27 @@
}
/**
+ * Marks the VPN network as metered. A VPN network is classified as metered when the user is
+ * sensitive to heavy data usage due to monetary costs and/or data limitations. In such
+ * cases, you should set this to {@code true} so that apps on the system can avoid doing
+ * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN
+ * network to inherit its meteredness from its underlying networks.
+ *
+ * <p>VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be
+ * considered metered by default.
+ *
+ * @param isMetered {@code true} if VPN network should be treated as metered regardless of
+ * underlying network meteredness
+ * @return this {@link Builder} object to facilitate chaining method calls
+ * @see #setUnderlyingNetworks(Networks[])
+ * @see ConnectivityManager#isActiveNetworkMetered()
+ */
+ public Builder setMetered(boolean isMetered) {
+ mConfig.isMetered = isMetered;
+ return this;
+ }
+
+ /**
* Create a VPN interface using the parameters supplied to this
* builder. The interface works on IP packets, and a file descriptor
* is returned for the application to access them. Each read
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 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/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 16aea31b..5b5a235 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -18,7 +18,6 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.Network;
@@ -51,7 +50,8 @@
public interface Event extends Parcelable {}
/** @hide */
- @UnsupportedAppUsage
+ @SystemApi
+ @TestApi
public IpConnectivityLog() {
}
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index d308246..04a2e6e 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -16,7 +16,8 @@
package android.net.metrics;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -24,19 +25,28 @@
* An event logged when the APF packet socket receives an RA packet.
* {@hide}
*/
+@SystemApi
+@TestApi
public final class RaEvent implements IpConnectivityLog.Event {
- public static final long NO_LIFETIME = -1L;
+ private static final long NO_LIFETIME = -1L;
// Lifetime in seconds of options found in a single RA packet.
// When an option is not set, the value of the associated field is -1;
+ /** @hide */
public final long routerLifetime;
+ /** @hide */
public final long prefixValidLifetime;
+ /** @hide */
public final long prefixPreferredLifetime;
+ /** @hide */
public final long routeInfoLifetime;
+ /** @hide */
public final long rdnssLifetime;
+ /** @hide */
public final long dnsslLifetime;
+ /** @hide */
public RaEvent(long routerLifetime, long prefixValidLifetime, long prefixPreferredLifetime,
long routeInfoLifetime, long rdnssLifetime, long dnsslLifetime) {
this.routerLifetime = routerLifetime;
@@ -47,6 +57,7 @@
this.dnsslLifetime = dnsslLifetime;
}
+ /** @hide */
private RaEvent(Parcel in) {
routerLifetime = in.readLong();
prefixValidLifetime = in.readLong();
@@ -56,6 +67,7 @@
dnsslLifetime = in.readLong();
}
+ /** @hide */
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(routerLifetime);
@@ -66,6 +78,7 @@
out.writeLong(dnsslLifetime);
}
+ /** @hide */
@Override
public int describeContents() {
return 0;
@@ -83,6 +96,7 @@
.toString();
}
+ /** @hide */
public static final Parcelable.Creator<RaEvent> CREATOR = new Parcelable.Creator<RaEvent>() {
public RaEvent createFromParcel(Parcel in) {
return new RaEvent(in);
@@ -102,47 +116,39 @@
long rdnssLifetime = NO_LIFETIME;
long dnsslLifetime = NO_LIFETIME;
- @UnsupportedAppUsage
public Builder() {
}
- @UnsupportedAppUsage
public RaEvent build() {
return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime,
routeInfoLifetime, rdnssLifetime, dnsslLifetime);
}
- @UnsupportedAppUsage
public Builder updateRouterLifetime(long lifetime) {
routerLifetime = updateLifetime(routerLifetime, lifetime);
return this;
}
- @UnsupportedAppUsage
public Builder updatePrefixValidLifetime(long lifetime) {
prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime);
return this;
}
- @UnsupportedAppUsage
public Builder updatePrefixPreferredLifetime(long lifetime) {
prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime);
return this;
}
- @UnsupportedAppUsage
public Builder updateRouteInfoLifetime(long lifetime) {
routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime);
return this;
}
- @UnsupportedAppUsage
public Builder updateRdnssLifetime(long lifetime) {
rdnssLifetime = updateLifetime(rdnssLifetime, lifetime);
return this;
}
- @UnsupportedAppUsage
public Builder updateDnsslLifetime(long lifetime) {
dnsslLifetime = updateLifetime(dnsslLifetime, lifetime);
return this;
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/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 141d33b..1f33693 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -19,6 +19,7 @@
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
+
import java.util.ArrayDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
@@ -70,7 +71,7 @@
* protected Long doInBackground(URL... urls) {
* int count = urls.length;
* long totalSize = 0;
- * for (int i = 0; i < count; i++) {
+ * for (int i = 0; i < count; i++) {
* totalSize += Downloader.downloadFile(urls[i]);
* publishProgress((int) ((i / (float) count) * 100));
* // Escape early if cancel() is called
@@ -158,13 +159,22 @@
* </ul>
*
* <h2>Memory observability</h2>
- * <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
- * operations are safe without explicit synchronizations.</p>
+ * <p>AsyncTask guarantees that all callback calls are synchronized to ensure the following
+ * without explicit synchronizations.</p>
* <ul>
- * <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
- * in {@link #doInBackground}.
- * <li>Set member fields in {@link #doInBackground}, and refer to them in
- * {@link #onProgressUpdate} and {@link #onPostExecute}.
+ * <li>The memory effects of {@link #onPreExecute}, and anything else
+ * executed before the call to {@link #execute}, including the construction
+ * of the AsyncTask object, are visible to {@link #doInBackground}.
+ * <li>The memory effects of {@link #doInBackground} are visible to
+ * {@link #onPostExecute}.
+ * <li>Any memory effects of {@link #doInBackground} preceding a call
+ * to {@link #publishProgress} are visible to the corresponding
+ * {@link #onProgressUpdate} call. (But {@link #doInBackground} continues to
+ * run, and care needs to be taken that later updates in {@link #doInBackground}
+ * do not interfere with an in-progress {@link #onProgressUpdate} call.)
+ * <li>Any memory effects preceding a call to {@link #cancel} are visible
+ * after a call to {@link #isCancelled} that returns true as a result, or
+ * during and after a resulting call to {@link #onCancelled}.
* </ul>
*
* <h2>Order of execution</h2>
@@ -388,6 +398,10 @@
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
*
+ * This will normally run on a background thread. But to better
+ * support testing frameworks, it is recommended that this also tolerates
+ * direct execution on the foreground thread, as part of the {@link #execute} call.
+ *
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
@@ -404,6 +418,8 @@
/**
* Runs on the UI thread before {@link #doInBackground}.
+ * Invoked directly by {@link #execute} or {@link #executeOnExecutor}.
+ * The default version does nothing.
*
* @see #onPostExecute
* @see #doInBackground
@@ -414,7 +430,10 @@
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
- * specified result is the value returned by {@link #doInBackground}.</p>
+ * specified result is the value returned by {@link #doInBackground}.
+ * To better support testing frameworks, it is recommended that this be
+ * written to tolerate direct execution as part of the execute() call.
+ * The default version does nothing.</p>
*
* <p>This method won't be invoked if the task was cancelled.</p>
*
@@ -432,6 +451,7 @@
/**
* Runs on the UI thread after {@link #publishProgress} is invoked.
* The specified values are the values passed to {@link #publishProgress}.
+ * The default version does nothing.
*
* @param values The values indicating progress.
*
@@ -466,7 +486,8 @@
/**
* <p>Applications should preferably override {@link #onCancelled(Object)}.
* This method is invoked by the default implementation of
- * {@link #onCancelled(Object)}.</p>
+ * {@link #onCancelled(Object)}.
+ * The default version does nothing.</p>
*
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
@@ -504,12 +525,16 @@
* an attempt to stop the task.</p>
*
* <p>Calling this method will result in {@link #onCancelled(Object)} being
- * invoked on the UI thread after {@link #doInBackground(Object[])}
- * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
- * is never invoked. After invoking this method, you should check the
- * value returned by {@link #isCancelled()} periodically from
- * {@link #doInBackground(Object[])} to finish the task as early as
- * possible.</p>
+ * invoked on the UI thread after {@link #doInBackground(Object[])} returns.
+ * Calling this method guarantees that onPostExecute(Object) is never
+ * subsequently invoked, even if <tt>cancel</tt> returns false, but
+ * {@link #onPostExecute} has not yet run. To finish the
+ * task as early as possible, check {@link #isCancelled()} periodically from
+ * {@link #doInBackground(Object[])}.</p>
+ *
+ * <p>This only requests cancellation. It never waits for a running
+ * background task to terminate, even if <tt>mayInterruptIfRunning</tt> is
+ * true.</p>
*
* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 518528d..27f7e22 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -16,25 +16,28 @@
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;
+
+import com.android.internal.util.Preconditions;
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 +50,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 +120,26 @@
* @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) {
- // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
- DumpstateListener dsListener = new DumpstateListener(listener);
-
+ public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
+ @Nullable ParcelFileDescriptor screenshotFd,
+ @NonNull BugreportParams params,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull BugreportCallback callback) {
+ Preconditions.checkNotNull(bugreportFd);
+ Preconditions.checkNotNull(params);
+ Preconditions.checkNotNull(executor);
+ Preconditions.checkNotNull(callback);
+ 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.getFileDescriptor(),
+ (screenshotFd != null
+ ? screenshotFd.getFileDescriptor() : new FileDescriptor()),
params.getMode(), dsListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -137,34 +158,48 @@
}
}
- private final class DumpstateListener extends IDumpstateListener.Stub
- implements DeathRecipient {
- private final BugreportListener mListener;
+ private final class DumpstateListener extends IDumpstateListener.Stub {
+ private final Executor mExecutor;
+ private final BugreportCallback mCallback;
- DumpstateListener(@Nullable BugreportListener listener) {
- mListener = listener;
- }
-
- @Override
- public void binderDied() {
- // TODO(b/111441001): implement
+ DumpstateListener(Executor executor, @Nullable BugreportCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
}
@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/DynamicAndroidManager.java b/core/java/android/os/DynamicAndroidManager.java
new file mode 100644
index 0000000..5238896
--- /dev/null
+++ b/core/java/android/os/DynamicAndroidManager.java
@@ -0,0 +1,188 @@
+/*
+ * 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.os;
+
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.gsi.GsiProgress;
+
+/**
+ * The DynamicAndroidManager offers a mechanism to use a new Android image temporarily. After the
+ * installation, the device can reboot into this image with a new created /data. This image will
+ * last until the next reboot and then the device will go back to the original image. However the
+ * installed image and the new created /data are not deleted but disabled. Thus the application can
+ * either re-enable the installed image by calling {@link #toggle} or use the {@link #remove} to
+ * delete it completely. In other words, there are three device states: no installation, installed
+ * and running. The procedure to install a DynamicAndroid starts with a {@link #startInstallation},
+ * followed by a series of {@link #write} and ends with a {@link commit}. Once the installation is
+ * complete, the device state changes from no installation to the installed state and a followed
+ * reboot will change its state to running. Note one instance of dynamic android can exist on a
+ * given device thus the {@link #startInstallation} will fail if the device is currently running a
+ * DynamicAndroid.
+ *
+ * @hide
+ */
+@SystemService(Context.DYNAMIC_ANDROID_SERVICE)
+public class DynamicAndroidManager {
+ private static final String TAG = "DynamicAndroidManager";
+
+ private final IDynamicAndroidService mService;
+
+ /** {@hide} */
+ public DynamicAndroidManager(IDynamicAndroidService service) {
+ mService = service;
+ }
+
+ /** The DynamicAndroidManager.Session represents a started session for the installation. */
+ public class Session {
+ private Session() {}
+ /**
+ * Write a chunk of the DynamicAndroid system image
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
+ * error.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean write(byte[] buf) {
+ try {
+ return mService.write(buf);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Finish write and make device to boot into the it after reboot.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is any native runtime
+ * error.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean commit() {
+ try {
+ return mService.commit();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+ /**
+ * Start DynamicAndroid installation. This call may take an unbounded amount of time. The caller
+ * may use another thread to call the getStartProgress() to get the progress.
+ *
+ * @param systemSize system size in bytes
+ * @param userdataSize userdata size in bytes
+ * @return {@code true} if the call succeeds. {@code false} either the device does not contain
+ * enough space or a DynamicAndroid is currently in use where the {@link #isInUse} would be
+ * true.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public Session startInstallation(long systemSize, long userdataSize) {
+ try {
+ if (mService.startInstallation(systemSize, userdataSize)) {
+ return new Session();
+ } else {
+ return null;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Query the progress of the current installation operation. This can be called while the
+ * installation is in progress.
+ *
+ * @return GsiProgress GsiProgress { int status; long bytes_processed; long total_bytes; } The
+ * status field can be IGsiService.STATUS_NO_OPERATION, IGsiService.STATUS_WORKING or
+ * IGsiService.STATUS_COMPLETE.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public GsiProgress getInstallationProgress() {
+ try {
+ return mService.getInstallationProgress();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Abort the installation process. Note this method must be called in a thread other than the
+ * one calling the startInstallation method as the startInstallation method will not return
+ * until it is finished.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installation
+ * currently.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean abort() {
+ try {
+ return mService.abort();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /** @return {@code true} if the device is running a dynamic android */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean isInUse() {
+ try {
+ return mService.isInUse();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /** @return {@code true} if the device has a dynamic android installed */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean isInstalled() {
+ try {
+ return mService.isInstalled();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Remove DynamicAndroid installation if present
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean remove() {
+ try {
+ return mService.remove();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ /**
+ * Enable DynamicAndroid when it's not enabled, otherwise, disable it.
+ *
+ * @return {@code true} if the call succeeds. {@code false} if there is no installed image.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ public boolean toggle() {
+ try {
+ return mService.toggle();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}
diff --git a/core/java/android/os/IDynamicAndroidService.aidl b/core/java/android/os/IDynamicAndroidService.aidl
new file mode 100644
index 0000000..0b28799
--- /dev/null
+++ b/core/java/android/os/IDynamicAndroidService.aidl
@@ -0,0 +1,87 @@
+/*
+ * 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.os;
+
+import android.gsi.GsiProgress;
+
+/** {@hide} */
+interface IDynamicAndroidService
+{
+ /**
+ * Start DynamicAndroid installation. This call may take 60~90 seconds. The caller
+ * may use another thread to call the getStartProgress() to get the progress.
+ *
+ * @param systemSize system size in bytes
+ * @param userdataSize userdata size in bytes
+ * @return true if the call succeeds
+ */
+ boolean startInstallation(long systemSize, long userdataSize);
+
+ /**
+ * Query the progress of the current installation operation. This can be called while
+ * the installation is in progress.
+ *
+ * @return GsiProgress
+ */
+ GsiProgress getInstallationProgress();
+
+ /**
+ * Abort the installation process. Note this method must be called in a thread other
+ * than the one calling the startInstallation method as the startInstallation
+ * method will not return until it is finished.
+ *
+ * @return true if the call succeeds
+ */
+ boolean abort();
+
+ /**
+ * @return true if the device is running an DynamicAnroid image
+ */
+ boolean isInUse();
+
+ /**
+ * @return true if the device has an DynamicAndroid image installed
+ */
+ boolean isInstalled();
+
+ /**
+ * Remove DynamicAndroid installation if present
+ *
+ * @return true if the call succeeds
+ */
+ boolean remove();
+
+ /**
+ * Enable DynamicAndroid when it's not enabled, otherwise, disable it.
+ *
+ * @return true if the call succeeds
+ */
+ boolean toggle();
+
+ /**
+ * Write a chunk of the DynamicAndroid system image
+ *
+ * @return true if the call succeeds
+ */
+ boolean write(in byte[] buf);
+
+ /**
+ * Finish write and make device to boot into the it after reboot.
+ *
+ * @return true if the call succeeds
+ */
+ boolean commit();
+}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
new file mode 100644
index 0000000..b568f15
--- /dev/null
+++ b/core/java/android/os/OWNERS
@@ -0,0 +1,2 @@
+# Zygote
+per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/java/android/os/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/UserHandle.java b/core/java/android/os/UserHandle.java
index 648c022..de41ce2 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -226,6 +226,7 @@
* @hide
*/
@TestApi
+ @SystemApi
public static @AppIdInt int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
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/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS
index 3c9bbf8..426f002 100644
--- a/core/java/android/service/dreams/OWNERS
+++ b/core/java/android/service/dreams/OWNERS
@@ -1,3 +1,3 @@
-dsandler@google.com
+dsandler@android.com
michaelwr@google.com
roosa@google.com
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index f2259b0..2ee72bf 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
@@ -389,9 +390,13 @@
}
private void initPrecompiledViews() {
+ initPrecompiledViews(
+ SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false));
+ }
+
+ private void initPrecompiledViews(boolean enablePrecompiledViews) {
+ mUseCompiledView = enablePrecompiledViews;
try {
- mUseCompiledView =
- SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
if (mUseCompiledView) {
mPrecompiledClassLoader = mContext.getClassLoader();
String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
@@ -409,6 +414,17 @@
}
mUseCompiledView = false;
}
+ if (!mUseCompiledView) {
+ mPrecompiledClassLoader = null;
+ }
+ }
+
+ /**
+ * @hide for use by CTS tests
+ */
+ @TestApi
+ public void setPrecompiledLayoutsEnabledForTesting(boolean enablePrecompiledLayouts) {
+ initPrecompiledViews(enablePrecompiledLayouts);
}
/**
diff --git a/core/java/com/android/internal/net/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..65b974b 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;
@@ -103,7 +104,9 @@
public boolean allowBypass;
public boolean allowIPv4;
public boolean allowIPv6;
+ public boolean isMetered = true;
public Network[] underlyingNetworks;
+ public ProxyInfo proxyInfo;
public void updateAllowedFamilies(InetAddress address) {
if (address instanceof Inet4Address) {
@@ -163,7 +166,9 @@
out.writeInt(allowBypass ? 1 : 0);
out.writeInt(allowIPv4 ? 1 : 0);
out.writeInt(allowIPv6 ? 1 : 0);
+ out.writeInt(isMetered ? 1 : 0);
out.writeTypedArray(underlyingNetworks, flags);
+ out.writeParcelable(proxyInfo, flags);
}
public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -188,7 +193,9 @@
config.allowBypass = in.readInt() != 0;
config.allowIPv4 = in.readInt() != 0;
config.allowIPv6 = in.readInt() != 0;
+ config.isMetered = in.readInt() != 0;
config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
+ config.proxyInfo = in.readParcelable(null);
return config;
}
@@ -220,6 +227,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/OWNERS b/core/java/com/android/internal/os/OWNERS
new file mode 100644
index 0000000..9283105
--- /dev/null
+++ b/core/java/com/android/internal/os/OWNERS
@@ -0,0 +1 @@
+per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 382542a..1048cb4 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,7 +102,23 @@
/** Read-write external storage should be mounted. */
public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
- private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+ /** 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;
/**
* An extraArg passed when a zygote process is forking a child-zygote, specifying a name
@@ -101,6 +127,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];
@@ -146,7 +211,7 @@
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
- VM_HOOKS.preFork();
+ ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
@@ -159,7 +224,7 @@
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
- VM_HOOKS.postForkCommon();
+ ZygoteHooks.postForkCommon();
return pid;
}
@@ -168,6 +233,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.
+ */
+ ZygoteHooks.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);
@@ -202,7 +310,7 @@
*/
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
- VM_HOOKS.preFork();
+ ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkSystemServer(
@@ -212,7 +320,7 @@
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
- VM_HOOKS.postForkCommon();
+ ZygoteHooks.postForkCommon();
return pid;
}
@@ -230,18 +338,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.
+ ZygoteHooks.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.
+ ZygoteHooks.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,15 +770,57 @@
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.
- VM_HOOKS.postForkSystemServer();
+ ZygoteHooks.postForkSystemServer();
}
private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
boolean isZygote, String instructionSet) {
- VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
+ ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
}
/**
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 43f114f..2bb0759 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -26,6 +26,7 @@
import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
+import android.metrics.LogMaker;
import android.net.Credentials;
import android.net.LocalSocket;
import android.os.Process;
@@ -35,6 +36,9 @@
import android.system.StructPollfd;
import android.util.Log;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -224,7 +228,7 @@
fdsToClose[0] = fd.getInt$();
}
- fd = zygoteServer.getServerSocketFileDescriptor();
+ fd = zygoteServer.getZygoteSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
@@ -311,9 +315,43 @@
}
}
- private void handleHiddenApiAccessLogSampleRate(int percent) {
+ private class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
+
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
+ public void hiddenApiUsed(String packageName, String signature,
+ int accessMethod, boolean accessDenied) {
+ int accessMethodMetric = HiddenApiUsageLogger.ACCESS_METHOD_NONE;
+ switch(accessMethod) {
+ case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
+ accessMethodMetric = MetricsEvent.ACCESS_METHOD_NONE;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
+ accessMethodMetric = MetricsEvent.ACCESS_METHOD_REFLECTION;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
+ accessMethodMetric = MetricsEvent.ACCESS_METHOD_JNI;
+ break;
+ case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
+ accessMethodMetric = MetricsEvent.ACCESS_METHOD_LINKING;
+ break;
+ }
+ LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_HIDDEN_API_ACCESSED)
+ .setPackageName(packageName)
+ .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_SIGNATURE, signature)
+ .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_METHOD,
+ accessMethodMetric);
+ if (accessDenied) {
+ logMaker.addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_DENIED, 1);
+ }
+ mMetricsLogger.write(logMaker);
+ }
+ }
+
+ private void handleHiddenApiAccessLogSampleRate(int samplingRate) {
try {
- ZygoteInit.setHiddenApiAccessLogSampleRate(percent);
+ ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
+ ZygoteInit.setHiddenApiUsageLogger(new HiddenApiUsageLogger());
mSocketOutStream.writeInt(0);
} catch (IOException ioe) {
throw new IllegalStateException("Error writing to command socket", ioe);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 2f00c07..9f23797 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;
@@ -533,6 +533,14 @@
}
/**
+ * Sets the implementation to be used for logging hidden API accesses
+ * @param logger the implementation of the VMRuntime.HiddenApiUsageLogger interface
+ */
+ public static void setHiddenApiUsageLogger(VMRuntime.HiddenApiUsageLogger logger) {
+ VMRuntime.getRuntime().setHiddenApiUsageLogger(logger);
+ }
+
+ /**
* Creates a PathClassLoader for the given class path that is associated with a shared
* namespace, i.e., this classloader can access platform-private native libraries. The
* classloader will use java.library.path as the native library path.
@@ -750,7 +758,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 +794,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 +847,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/OWNERS b/core/jni/OWNERS
index a365a56..774c224 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -3,4 +3,7 @@
per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhijunhe@google.com
# Connectivity
-per-file android_net_* = ek@google.com, lorenzo@google.com, satk@google.com
+per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
+
+# Zygote
+per-file com_android_inernal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 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_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 7eddcfe..cfb2dd1 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -29,6 +29,7 @@
#include <net/if.h>
#include <linux/filter.h>
#include <linux/if_arp.h>
+#include <linux/tcp.h>
#include <netinet/ether.h>
#include <netinet/icmp6.h>
#include <netinet/ip.h>
@@ -226,6 +227,34 @@
}
}
+static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ struct sock_filter filter_code[] = {
+ // Reject all.
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ struct sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ int dummy = 0;
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_DETACH_FILTER): %s", strerror(errno));
+ }
+
+}
static void android_net_utils_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
jint ifIndex)
{
@@ -458,6 +487,41 @@
return answer;
}
+static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
+ if (javaFd == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return NULL;
+ }
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ struct tcp_repair_window trw = {};
+ socklen_t size = sizeof(trw);
+
+ // Obtain the parameters of the TCP repair window.
+ int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
+ if (rc == -1) {
+ throwErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
+ return NULL;
+ }
+
+ struct tcp_info tcpinfo = {};
+ socklen_t tcpinfo_size = sizeof(tcp_info);
+
+ // Obtain the window scale from the tcp info structure. This contains a scale factor that
+ // should be applied to the window size.
+ rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
+ if (rc == -1) {
+ throwErrnoException(env, "getsockopt : TCP_INFO", errno);
+ return NULL;
+ }
+
+ jclass class_TcpRepairWindow = env->FindClass("android/net/TcpRepairWindow");
+ jmethodID ctor = env->GetMethodID(class_TcpRepairWindow, "<init>", "(IIIIII)V");
+
+ return env->NewObject(class_TcpRepairWindow, ctor, trw.snd_wl1, trw.snd_wnd, trw.max_window,
+ trw.rcv_wnd, trw.rcv_wup, tcpinfo.tcpi_rcv_wscale);
+}
+
// ----------------------------------------------------------------------------
/*
@@ -475,6 +539,9 @@
{ "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
{ "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
{ "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
+ { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
+ { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
+ { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
{ "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
{ "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
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_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index e64d2af..ee11b61 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -96,7 +96,7 @@
return toJavaStringArray(env, cStrings);
}
-static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckFlags::Type checks) {
+static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
std::vector<std::string> cPackageInfo;
if (packageInfo) {
size_t count = env->GetArrayLength(packageInfo);
@@ -109,18 +109,19 @@
}
}
std::string error;
- int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error, checks);
+ int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error);
if (status)
LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error;
return status;
}
-static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
- return verify(env, packageInfo, ::android::vintf::CheckFlags::ENABLE_ALL_CHECKS);
-}
-
static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) {
- return verify(env, nullptr, ::android::vintf::CheckFlags::DISABLE_AVB_CHECK);
+ std::string error;
+ int32_t status = VintfObject::CheckCompatibility({}, &error,
+ ::android::vintf::CheckFlags::DISABLE_AVB_CHECK);
+ if (status)
+ LOG(WARNING) << "VintfObject.verifyWithoutAvb() returns " << status << ": " << error;
+ return status;
}
static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 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..32ddad1 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"
@@ -346,30 +346,34 @@
static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
{
FILE *file;
- const char *filename;
+ std::string filename;
CPU_ZERO(cpu_set);
switch (policy) {
case SP_BACKGROUND:
- filename = "/dev/cpuset/background/cpus";
+ if (!CgroupGetAttributePath("LowCapacityCPUs", &filename)) {
+ return;
+ }
break;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
case SP_RT_APP:
- filename = "/dev/cpuset/foreground/cpus";
+ if (!CgroupGetAttributePath("HighCapacityCPUs", &filename)) {
+ return;
+ }
break;
case SP_TOP_APP:
- filename = "/dev/cpuset/top-app/cpus";
+ if (!CgroupGetAttributePath("MaxCapacityCPUs", &filename)) {
+ return;
+ }
break;
default:
- filename = NULL;
+ return;
}
- if (!filename) return;
-
- file = fopen(filename, "re");
+ file = fopen(filename.c_str(), "re");
if (file != NULL) {
// Parse cpus string
char *line = NULL;
@@ -379,7 +383,7 @@
if (num_read > 0) {
parse_cpuset_cpus(line, cpu_set);
} else {
- ALOGE("Failed to read %s", filename);
+ ALOGE("Failed to read %s", filename.c_str());
}
free(line);
}
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..3012c90 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);
@@ -1305,15 +1305,12 @@
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}
- bool low_ram_device = GetBoolProperty("ro.config.low_ram", false);
- bool per_app_memcg = GetBoolProperty("ro.config.per_app_memcg", low_ram_device);
- if (per_app_memcg) {
+ if (UsePerAppMemcg()) {
// Assign system_server to the correct memory cgroup.
- // Not all devices mount /dev/memcg so check for the file first
+ // Not all devices mount memcg so check if it is mounted first
// to avoid unnecessarily printing errors and denials in the logs.
- if (!access("/dev/memcg/system/tasks", F_OK) &&
- !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
- ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
+ if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
+ ALOGE("couldn't add process %d into system memcg group", pid);
}
}
}
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/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index b70bb67..21717d8 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -41,7 +41,7 @@
RADIO_TECHNOLOGY_UMTS = 3;
RADIO_TECHNOLOGY_IS95A = 4;
RADIO_TECHNOLOGY_IS95B = 5;
- RADIO_TECHNOLOGY_1xRTT = 6;
+ RADIO_TECHNOLOGY_1XRTT = 6;
RADIO_TECHNOLOGY_EVDO_0 = 7;
RADIO_TECHNOLOGY_EVDO_A = 8;
RADIO_TECHNOLOGY_HSDPA = 9;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 344b74c..7590675 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -481,6 +481,7 @@
<protected-broadcast android:name="android.security.action.TRUST_STORE_CHANGED" />
<protected-broadcast android:name="android.security.action.KEYCHAIN_CHANGED" />
<protected-broadcast android:name="android.security.action.KEY_ACCESS_CHANGED" />
+ <protected-broadcast android:name="android.telecom.action.NUISANCE_CALL_STATUS_CHANGED" />
<protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
<protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
<protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" />
@@ -1554,7 +1555,7 @@
<permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"
android:protectionLevel="signature|privileged" />
- <!-- Allows a system application to access hardware packet offload capabilities.
+ <!-- @SystemApi Allows a system application to access hardware packet offload capabilities.
@hide -->
<permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
android:protectionLevel="signature|privileged" />
@@ -1681,6 +1682,10 @@
<permission android:name="android.permission.HARDWARE_TEST"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to manage DynamicAndroid image -->
+ <permission android:name="android.permission.MANAGE_DYNAMIC_ANDROID"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows access to Broadcast Radio
@hide This is not a third-party API (intended for system apps).-->
<permission android:name="android.permission.ACCESS_BROADCAST_RADIO"
@@ -3231,6 +3236,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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8518c70..b412f0f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3202,6 +3202,9 @@
<!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
<string name="wifi_no_internet_detailed">Tap for options</string>
+ <!-- A notification is shown after the user logs in to a captive portal network, to indicate that the network should now have internet connectivity. This is the message of notification. [CHAR LIMIT=50] -->
+ <string name="captive_portal_logged_in_detailed">Connected</string>
+
<!-- A notification is shown when the user's softap config has been changed due to underlying
hardware restrictions. This is the notifications's title.
[CHAR_LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8d832ca..92fdd1d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -690,6 +690,7 @@
<java-symbol type="string" name="capability_title_canControlMagnification" />
<java-symbol type="string" name="capability_desc_canPerformGestures" />
<java-symbol type="string" name="capability_title_canPerformGestures" />
+ <java-symbol type="string" name="captive_portal_logged_in_detailed" />
<java-symbol type="string" name="cfTemplateForwarded" />
<java-symbol type="string" name="cfTemplateForwardedTime" />
<java-symbol type="string" name="cfTemplateNotForwarded" />
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/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
index c64d520..f0c9032 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java
@@ -47,21 +47,11 @@
}
/**
- * Detect when the org.apache.http.legacy is not on the bootclasspath.
- *
- * <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
- * succeed otherwise. This allows a developer to ensure that the tests are being
- */
- @Test
- public void detectWhenOAHLisOnBCP() {
- Assume.assumeTrue(PackageBackwardCompatibility.bootClassPathContainsOAHL());
- }
-
- /**
* Detect when the android.test.base is not on the bootclasspath.
*
* <p>This test will be ignored when org.apache.http.legacy is not on the bootclasspath and
- * succeed otherwise. This allows a developer to ensure that the tests are being
+ * succeed otherwise. This allows a developer to ensure that the tests are being run in the
+ * correct environment.
*/
@Test
public void detectWhenATBisOnBCP() {
@@ -84,9 +74,7 @@
if (!PackageBackwardCompatibility.bootClassPathContainsATB()) {
expected.add(ANDROID_TEST_BASE);
}
- if (!PackageBackwardCompatibility.bootClassPathContainsOAHL()) {
- expected.add(ORG_APACHE_HTTP_LEGACY);
- }
+ expected.add(ORG_APACHE_HTTP_LEGACY);
PackageBuilder after = builder()
.targetSdkVersion(Build.VERSION_CODES.O)
@@ -97,30 +85,6 @@
/**
* Ensures that the {@link PackageBackwardCompatibility} uses
- * {@link RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest}
- * when necessary.
- *
- * <p>More comprehensive tests for that class can be found in
- * {@link RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest}.
- */
- @Test
- public void org_apache_http_legacy_in_usesLibraries() {
- Assume.assumeTrue("Test requires that "
- + ORG_APACHE_HTTP_LEGACY + " is on the bootclasspath",
- PackageBackwardCompatibility.bootClassPathContainsOAHL());
-
- PackageBuilder before = builder()
- .requiredLibraries(ORG_APACHE_HTTP_LEGACY);
-
- // org.apache.http.legacy should be removed from the libraries because it is provided
- // on the bootclasspath and providing both increases start up cost unnecessarily.
- PackageBuilder after = builder();
-
- checkBackwardsCompatibility(before, after);
- }
-
- /**
- * Ensures that the {@link PackageBackwardCompatibility} uses
* {@link RemoveUnnecessaryAndroidTestBaseLibrary}
* when necessary.
*
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/data/etc/Android.bp b/data/etc/Android.bp
index 035ee10..bb47658 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -58,6 +58,14 @@
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.dialer",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.dialer.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.launcher3",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.dialer.xml b/data/etc/com.android.dialer.xml
new file mode 100644
index 0000000..ccdb21f
--- /dev/null
+++ b/data/etc/com.android.dialer.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.dialer">
+ <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/>
+ <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+ <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c9f0f10..9a148e4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -48,17 +48,6 @@
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.dialer">
- <permission name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"/>
- <permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
- <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.STOP_APP_SWITCHES"/>
- <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
- <permission name="com.android.voicemail.permission.WRITE_VOICEMAIL"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.emergency">
<!-- Required to place emergency calls from emergency info screen. -->
<permission name="android.permission.CALL_PRIVILEGED"/>
diff --git a/keystore/java/android/security/OWNERS b/keystore/java/android/security/OWNERS
new file mode 100644
index 0000000..ed30587
--- /dev/null
+++ b/keystore/java/android/security/OWNERS
@@ -0,0 +1 @@
+per-file *.java,*.aidl = eranm@google.com,pgrafov@google.com,rubinxu@google.com
diff --git a/keystore/tests/OWNERS b/keystore/tests/OWNERS
new file mode 100644
index 0000000..9e65f88
--- /dev/null
+++ b/keystore/tests/OWNERS
@@ -0,0 +1,5 @@
+# Android Enterprise security team
+eranm@google.com
+irinaid@google.com
+pgrafov@google.com
+rubinxu@google.com
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 4c563db..25c7b5c 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -51,6 +51,7 @@
"libmtp",
"libexif",
"libpiex",
+ "libprocessgroup",
"libandroidfw",
"libhidlallocatorutils",
"libhidlbase",
@@ -131,6 +132,7 @@
"libcutils",
"libdexfile",
"liblzma",
+ "libjsoncpp",
"libmedia_helper",
"libmedia_player2_util",
"libmediadrm",
@@ -140,6 +142,7 @@
"libmediautils",
"libnativehelper",
"libnetd_client",
+ "libprocessgroup",
"libstagefright_esds",
"libstagefright_foundation",
"libstagefright_httplive",
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
new file mode 100644
index 0000000..4ac652a
--- /dev/null
+++ b/packages/CaptivePortalLogin/Android.bp
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+
+android_app {
+ name: "CaptivePortalLogin",
+ srcs: ["src/**/*.java"],
+ sdk_version: "system_current",
+ certificate: "platform",
+ static_libs: [
+ "android-support-v4",
+ "metrics-constants-protos",
+ ],
+ manifest: "AndroidManifest.xml",
+}
diff --git a/packages/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
deleted file mode 100644
index 7dc23ff..0000000
--- a/packages/CaptivePortalLogin/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CaptivePortalLogin
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index c84f3ec..e15dca0 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -21,7 +21,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
diff --git a/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml b/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml
deleted file mode 100644
index d460041..0000000
--- a/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ssl_error_msg"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_marginStart="20dip"
- android:layout_marginEnd="20dip"
- android:gravity="center_vertical"
- android:layout_marginBottom="4dip"
- android:layout_marginTop="4dip" />
-
diff --git a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
index ffd57a4..ce05e78 100644
--- a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
+++ b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml
@@ -78,7 +78,18 @@
android:id="@+id/certificate_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="vertical"
android:layout_marginBottom="16dip" >
+ <TextView
+ android:id="@+id/ssl_error_msg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_marginStart="20dip"
+ android:layout_marginEnd="20dip"
+ android:gravity="center_vertical"
+ android:layout_marginBottom="4dip"
+ android:layout_marginTop="16dip" />
</LinearLayout>
</ScrollView>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 7e20f2d..9b70ff3 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -17,11 +17,10 @@
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;
-import android.app.LoadedApk;
+import android.app.Application;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -38,9 +37,9 @@
import android.net.http.SslCertificate;
import android.net.http.SslError;
import android.net.wifi.WifiInfo;
-import android.os.Build;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.provider.Settings;
+import android.os.SystemProperties;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -61,16 +60,14 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
-import java.lang.InterruptedException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -81,6 +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),
@@ -98,6 +96,7 @@
private CaptivePortal mCaptivePortal;
private NetworkCallback mNetworkCallback;
private ConnectivityManager mCm;
+ private WifiManager mWifiManager;
private boolean mLaunchBrowser = false;
private MyWebViewClient mWebViewClient;
private SwipeRefreshLayout mSwipeRefreshLayout;
@@ -108,11 +107,12 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
- mCm = ConnectivityManager.from(this);
+ mCm = getSystemService(ConnectivityManager.class);
+ mWifiManager = getSystemService(WifiManager.class);
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
- mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
mUserAgent =
getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT);
mUrl = getUrl();
@@ -153,7 +153,6 @@
// Also initializes proxy system properties.
mNetwork = mNetwork.getPrivateDnsBypassingCopy();
mCm.bindProcessToNetwork(mNetwork);
- mCm.setProcessDefaultNetworkForHostResolution(mNetwork);
// Proxy system properties must be initialized before setContentView is called because
// setContentView initializes the WebView logic which in turn reads the system properties.
@@ -192,9 +191,12 @@
// Find WebView's proxy BroadcastReceiver and prompt it to read proxy system properties.
private void setWebViewProxy() {
- LoadedApk loadedApk = getApplication().mLoadedApk;
+ // TODO: migrate to androidx WebView proxy setting API as soon as it is finalized
try {
- Field receiversField = LoadedApk.class.getDeclaredField("mReceivers");
+ final Field loadedApkField = Application.class.getDeclaredField("mLoadedApk");
+ final Class<?> loadedApkClass = loadedApkField.getType();
+ final Object loadedApk = loadedApkField.get(getApplication());
+ Field receiversField = loadedApkClass.getDeclaredField("mReceivers");
receiversField.setAccessible(true);
ArrayMap receivers = (ArrayMap) receiversField.get(loadedApk);
for (Object receiverMap : receivers.values()) {
@@ -335,7 +337,11 @@
private static String sanitizeURL(URL url) {
// In non-Debug build, only show host to avoid leaking private info.
- return Build.IS_DEBUGGABLE ? Objects.toString(url) : host(url);
+ return isDebuggable() ? Objects.toString(url) : host(url);
+ }
+
+ private static boolean isDebuggable() {
+ return SystemProperties.getInt("ro.debuggable", 0) == 1;
}
private void testForCaptivePortal() {
@@ -588,19 +594,18 @@
}
private void setViewSecurityCertificate(LinearLayout certificateLayout, SslError error) {
+ ((TextView) certificateLayout.findViewById(R.id.ssl_error_msg))
+ .setText(sslErrorMessage(error));
SslCertificate cert = error.getCertificate();
-
- View certificateView = cert.inflateCertificateView(CaptivePortalLoginActivity.this);
- final LinearLayout placeholder = (LinearLayout) certificateView
- .findViewById(com.android.internal.R.id.placeholder);
- LayoutInflater factory = LayoutInflater.from(CaptivePortalLoginActivity.this);
-
- TextView textView = (TextView) factory.inflate(
- R.layout.ssl_error_msg, placeholder, false);
- textView.setText(sslErrorMessage(error));
- placeholder.addView(textView);
-
- certificateLayout.addView(certificateView);
+ // TODO: call the method directly once inflateCertificateView is @SystemApi
+ try {
+ final View certificateView = (View) SslCertificate.class.getMethod(
+ "inflateCertificateView", Context.class)
+ .invoke(cert, CaptivePortalLoginActivity.this);
+ certificateLayout.addView(certificateView);
+ } catch (ReflectiveOperationException | SecurityException e) {
+ Log.e(TAG, "Could not create certificate view", e);
+ }
}
}
@@ -621,11 +626,30 @@
private String getHeaderTitle() {
NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
- if (nc == null || TextUtils.isEmpty(nc.getSSID())
- || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ final String ssid = getSsid();
+ if (TextUtils.isEmpty(ssid)
+ || nc == null || !nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return getString(R.string.action_bar_label);
}
- return getString(R.string.action_bar_title, WifiInfo.removeDoubleQuotes(nc.getSSID()));
+ return getString(R.string.action_bar_title, ssid);
+ }
+
+ // TODO: remove once SSID is obtained from NetworkCapabilities
+ private String getSsid() {
+ if (mWifiManager == null) {
+ return null;
+ }
+ final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ return removeDoubleQuotes(wifiInfo.getSSID());
+ }
+
+ private static String removeDoubleQuotes(String string) {
+ if (string == null) return null;
+ final int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
}
private String getHeaderSubtitle(URL url) {
@@ -638,7 +662,7 @@
}
private void logMetricsEvent(int event) {
- MetricsLogger.action(this, event, getPackageName());
+ mCaptivePortal.logEvent(event, getPackageName());
}
private static final SparseArray<String> SSL_ERRORS = new SparseArray<>();
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index a2da0a0..d656593 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -18,24 +18,28 @@
// 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: [
"NetworkStackLib"
],
manifest: "AndroidManifest.xml",
+ required: ["NetworkStackPermissionStub"],
}
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 5ab833b..ac55bfa 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -25,6 +25,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
+ <!-- Signature permission defined in NetworkStackStub -->
+ <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
<!-- Launch captive portal app as specific user -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
diff --git a/packages/NetworkStack/OWNERS b/packages/NetworkStack/OWNERS
new file mode 100644
index 0000000..a395465
--- /dev/null
+++ b/packages/NetworkStack/OWNERS
@@ -0,0 +1,5 @@
+codewiz@google.com
+jchalard@google.com
+lorenzo@google.com
+reminv@google.com
+satk@google.com
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..dbffa6d 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;
@@ -109,6 +109,8 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
+ // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate
+ private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
// Default configuration values for captive portal detection probes.
// TODO: append a random length parameter to the default HTTPS url.
// TODO: randomize browser version ids in the default User-Agent String.
@@ -309,14 +311,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 +370,7 @@
// we can ever fetch them.
// TODO: Delete ASAP.
mLinkProperties = new LinkProperties();
- mNetworkCapabilities = new NetworkCapabilities();
- mNetworkCapabilities.clearAll();
+ mNetworkCapabilities = new NetworkCapabilities(null);
}
/**
@@ -683,11 +684,20 @@
public void appResponse(int response) {
if (response == APP_RETURN_WANTED_AS_IS) {
mContext.enforceCallingPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ PERMISSION_NETWORK_SETTINGS,
"CaptivePortal");
}
sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
}
+
+ @Override
+ public void logEvent(int eventId, String packageName)
+ throws RemoteException {
+ mContext.enforceCallingPermission(
+ PERMISSION_NETWORK_SETTINGS,
+ "CaptivePortal");
+ mCallback.logCaptivePortalLoginEvent(eventId, packageName);
+ }
}));
final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
@@ -1146,7 +1156,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 +1182,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/src/com/android/server/util/PermissionUtil.java b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
index 82bf038..f6eb900 100644
--- a/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
+++ b/packages/NetworkStack/src/com/android/server/util/PermissionUtil.java
@@ -19,6 +19,7 @@
import static android.os.Binder.getCallingUid;
import android.os.Process;
+import android.os.UserHandle;
/**
* Utility class to check calling permissions on the network stack.
@@ -32,7 +33,7 @@
public static void checkNetworkStackCallingPermission() {
// TODO: check that the calling PID is the system server.
final int caller = getCallingUid();
- if (caller != Process.SYSTEM_UID && caller != Process.BLUETOOTH_UID) {
+ if (caller != Process.SYSTEM_UID && UserHandle.getAppId(caller) != Process.BLUETOOTH_UID) {
throw new SecurityException("Invalid caller: " + caller);
}
}
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/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkStackPermissionStub/Android.bp
new file mode 100644
index 0000000..94870c9
--- /dev/null
+++ b/packages/NetworkStackPermissionStub/Android.bp
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+
+// Stub APK to define permissions for NetworkStack
+android_app {
+ name: "NetworkStackPermissionStub",
+ // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
+ // a classes.dex.
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+ manifest: "AndroidManifest.xml",
+}
diff --git a/packages/NetworkStackPermissionStub/AndroidManifest.xml b/packages/NetworkStackPermissionStub/AndroidManifest.xml
new file mode 100644
index 0000000..2ccf5ff
--- /dev/null
+++ b/packages/NetworkStackPermissionStub/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.mainline.networkstack.permissionstub">
+ <!--
+ This package only exists to define the below permissions, and enforce that they are only
+ granted to apps sharing the same signature.
+ Permissions defined here are intended to be used only by the NetworkStack: both
+ NetworkStack and this stub APK are to be signed with a dedicated certificate to ensure
+ that, with the below permissions being signature permissions.
+
+ This APK *must* be installed, even if the NetworkStack app is not installed, because otherwise,
+ any application will be able to define this permission and the system will give that application
+ full access to the network stack.
+ -->
+ <permission android:name="android.permission.MAINLINE_NETWORK_STACK"
+ android:protectionLevel="signature"/>
+
+ <application android:name="com.android.server.NetworkStackPermissionStub"/>
+</manifest>
\ No newline at end of file
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
similarity index 62%
rename from services/net/java/android/net/dhcp/DhcpClient.java
rename to packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
index cddb91f..01e59d2 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-package android.net.dhcp;
+package com.android.server;
+
+import android.app.Application;
/**
- * TODO: remove this class after migrating clients.
+ * Empty application for NetworkStackStub that only exists because soong builds complain if APKs
+ * have no source file.
*/
-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;
+public class NetworkStackPermissionStub extends Application {
}
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index d188c65..d879087 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -4,7 +4,7 @@
dehboxturtle@google.com
dhnishi@google.com
dling@google.com
-dsandler@google.com
+dsandler@android.com
evanlaird@google.com
jackqdyulei@google.com
jmonk@google.com
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 76a216d..23e13c2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -191,9 +191,9 @@
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec">HD audio</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the Hearing Aid profile. -->
- <string name="bluetooth_profile_hearing_aid">Hearing Aid</string>
+ <string name="bluetooth_profile_hearing_aid">Hearing Aids</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference when Hearing Aid is connected. -->
- <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aid</string>
+ <string name="bluetooth_hearing_aid_profile_summary_connected">Connected to Hearing Aids</string>
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
@@ -233,7 +233,7 @@
will set the HID profile as preferred. -->
<string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
<!-- Bluetooth settings. Connection options screen. The summary for the Hearing Aid checkbox preference that describes how checking it will set the Hearing Aid profile as preferred. -->
- <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aid</string>
+ <string name="bluetooth_hearing_aid_profile_summary_use_for">Use for Hearing Aids</string>
<!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
<string name="bluetooth_pairing_accept">Pair</string>
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 2a3cf3e..3f6ebf0 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -1,6 +1,6 @@
set noparent
-dsandler@google.com
+dsandler@android.com
adamcohen@google.com
asc@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
old mode 100755
new mode 100644
index 8450b74..7a64f5a
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -35,6 +35,7 @@
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -242,7 +243,8 @@
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
- mContext.registerReceiver(mBroadcastReceiver, intentFilter);
+ mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter,
+ null, null);
if (sSettingsPackageAndClassNamePairList == null) {
String[] settings = mContext.getResources().getStringArray(
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 8172e71..1d0b9b6 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="com.android.vpndialogs">
<uses-permission android:name="android.permission.CONTROL_VPN" />
+ <uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<application android:label="VpnDialogs"
diff --git a/proto/Android.bp b/proto/Android.bp
index f3811bd..9b7a1c1 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -17,3 +17,24 @@
},
},
}
+
+java_library_static {
+ name: "metrics-constants-protos",
+ host_supported: true,
+ proto: {
+ type: "nano",
+ },
+ srcs: ["src/metrics_constants.proto"],
+ no_framework_libs: true,
+ sdk_version: "system_current",
+ // Pin java_version until jarjar is certified to support later versions. http://b/72703434
+ java_version: "1.8",
+ target: {
+ android: {
+ jarjar_rules: "jarjar-rules.txt",
+ },
+ host: {
+ static_libs: ["libprotobuf-java-nano"],
+ },
+ },
+}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index fba639c..8ee55e1 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -231,6 +231,8 @@
NOTE_NETWORK_LOST_INTERNET = 742;
// The system default network switched to a different network
NOTE_NETWORK_SWITCH = 743;
+ // Device logged-in captive portal network successfully
+ NOTE_NETWORK_LOGGED_IN = 744;
// Notify the user that their work profile has been deleted
// Package: android
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9b8f51e..48b69b0 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -7,6 +7,7 @@
"frameworks/native/cmds/dumpstate/binder",
"system/core/storaged/binder",
"system/vold/binder",
+ "system/gsid/aidl",
],
},
srcs: [
@@ -15,6 +16,7 @@
":installd_aidl",
":storaged_aidl",
":vold_aidl",
+ ":gsiservice_aidl",
":mediaupdateservice_aidl",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
@@ -45,7 +47,7 @@
"android.hardware.vibrator-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
- "android.hidl.manager-V1.0-java",
+ "android.hidl.manager-V1.2-java",
"netd_aidl_interface-java",
"netd_event_listener_interface-java",
],
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fda7279..b98d7a1 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;
@@ -59,7 +60,6 @@
import android.database.ContentObserver;
import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
import android.net.IIpConnectivityMetrics;
import android.net.INetd;
@@ -92,6 +92,7 @@
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.Uri;
import android.net.VpnService;
@@ -101,7 +102,7 @@
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
-import android.net.shared.NetdService;
+import android.net.util.NetdService;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -144,6 +145,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
@@ -238,6 +240,9 @@
// connect anyway?" dialog after the user selects a network that doesn't validate.
private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
+ // How long to dismiss network notification.
+ private static final int TIMEOUT_NOTIFICATION_DELAY_MS = 20 * 1000;
+
// Default to 30s linger time-out. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
@@ -474,6 +479,11 @@
public static final int EVENT_PROVISIONING_NOTIFICATION = 43;
/**
+ * This event can handle dismissing notification by given network id.
+ */
+ public static final int EVENT_TIMEOUT_NOTIFICATION = 44;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -507,7 +517,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;
@@ -816,7 +827,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();
@@ -982,6 +993,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);
@@ -1870,6 +1886,12 @@
"ConnectivityService");
}
+ private void enforceControlAlwaysOnVpnPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+ "ConnectivityService");
+ }
+
private void enforceNetworkStackSettingsOrSetup() {
enforceAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -1877,6 +1899,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);
@@ -2459,8 +2487,8 @@
nai.networkMisc.acceptUnvalidated = msg.arg1 == 1;
break;
}
- case NetworkAgent.EVENT_PACKET_KEEPALIVE: {
- mKeepaliveTracker.handleEventPacketKeepalive(nai, msg);
+ case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
+ mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
break;
}
}
@@ -2477,6 +2505,11 @@
final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
final boolean wasValidated = nai.lastValidated;
final boolean wasDefault = isDefaultNetwork(nai);
+ if (nai.everCaptivePortalDetected && !nai.captivePortalLoginNotified
+ && valid) {
+ nai.captivePortalLoginNotified = true;
+ showNetworkNotification(nai, NotificationType.LOGGED_IN);
+ }
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
@@ -2497,7 +2530,15 @@
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
- if (valid) handleFreshlyValidatedNetwork(nai);
+ if (valid) {
+ handleFreshlyValidatedNetwork(nai);
+ // Clear NO_INTERNET and LOST_INTERNET notifications if network becomes
+ // valid.
+ mNotifier.clearNotification(nai.network.netId,
+ NotificationType.NO_INTERNET);
+ mNotifier.clearNotification(nai.network.netId,
+ NotificationType.LOST_INTERNET);
+ }
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -2521,6 +2562,9 @@
final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
+ if (visible) {
+ nai.captivePortalLoginNotified = false;
+ }
if (nai.lastCaptivePortalDetected &&
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
if (DBG) log("Avoiding captive portal network: " + nai.name());
@@ -2532,7 +2576,10 @@
updateCapabilities(oldScore, nai, nai.networkCapabilities);
}
if (!visible) {
- mNotifier.clearNotification(netId);
+ // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other
+ // notifications belong to the same network may be cleared unexpected.
+ mNotifier.clearNotification(netId, NotificationType.SIGN_IN);
+ mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH);
} else {
if (nai == null) {
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
@@ -2638,6 +2685,11 @@
EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
mNai.network.netId));
}
+
+ @Override
+ public void logCaptivePortalLoginEvent(int eventId, String packageName) {
+ new MetricsLogger().action(eventId, packageName);
+ }
}
private boolean networkRequiresValidation(NetworkAgentInfo nai) {
@@ -2801,8 +2853,7 @@
// sending all CALLBACK_LOST messages (for requests, not listens) at the end
// of rematchAllNetworksAndRequests
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
- mKeepaliveTracker.handleStopAllKeepalives(nai,
- ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+ mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
for (String iface : nai.linkProperties.getAllInterfaceNames()) {
// Disable wakeup packet monitoring for each interface.
wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3238,9 +3289,15 @@
pw.decreaseIndent();
}
- private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
+ private void showNetworkNotification(NetworkAgentInfo nai, NotificationType type) {
final String action;
switch (type) {
+ case LOGGED_IN:
+ action = Settings.ACTION_WIFI_SETTINGS;
+ mHandler.removeMessages(EVENT_TIMEOUT_NOTIFICATION);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NOTIFICATION,
+ nai.network.netId, 0), TIMEOUT_NOTIFICATION_DELAY_MS);
+ break;
case NO_INTERNET:
action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
break;
@@ -3253,10 +3310,12 @@
}
Intent intent = new Intent(action);
- intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setClassName("com.android.settings",
- "com.android.settings.wifi.WifiNoInternetDialog");
+ if (type != NotificationType.LOGGED_IN) {
+ intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setClassName("com.android.settings",
+ "com.android.settings.wifi.WifiNoInternetDialog");
+ }
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
@@ -3274,7 +3333,7 @@
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
return;
}
- showValidationNotification(nai, NotificationType.NO_INTERNET);
+ showNetworkNotification(nai, NotificationType.NO_INTERNET);
}
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
@@ -3283,7 +3342,7 @@
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
- showValidationNotification(nai, NotificationType.LOST_INTERNET);
+ showNetworkNotification(nai, NotificationType.LOST_INTERNET);
}
}
@@ -3386,12 +3445,12 @@
break;
}
// Sent by KeepaliveTracker to process an app request on the state machine thread.
- case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
+ case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: {
mKeepaliveTracker.handleStartKeepalive(msg);
break;
}
// Sent by KeepaliveTracker to process an app request on the state machine thread.
- case NetworkAgent.CMD_STOP_PACKET_KEEPALIVE: {
+ case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: {
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj);
int slot = msg.arg1;
int reason = msg.arg2;
@@ -3429,6 +3488,9 @@
case EVENT_DATA_SAVER_CHANGED:
handleRestrictBackgroundChanged(toBool(msg.arg1));
break;
+ case EVENT_TIMEOUT_NOTIFICATION:
+ mNotifier.clearNotification(msg.arg1, NotificationType.LOGGED_IN);
+ break;
}
}
}
@@ -3580,6 +3642,20 @@
mTethering.stopTethering(type);
}
+ /**
+ * Get the latest value of the tethering entitlement check.
+ *
+ * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
+ * out some such apps are observed to abuse this API, change to per-UID limits on this API
+ * if it's really needed.
+ */
+ @Override
+ public void getLatestTetheringEntitlementValue(int type, ResultReceiver receiver,
+ boolean showEntitlementUi, String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
+ mTethering.getLatestTetheringEntitlementValue(type, receiver, showEntitlementUi);
+ }
+
// Called when we lose the default network and have no replacement yet.
// This will automatically be cleared after X seconds or a new default network
// becomes CONNECTED, whichever happens first. The timer is started by the
@@ -3686,20 +3762,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);
}
}
@@ -3723,11 +3825,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();
@@ -4078,8 +4179,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) {
@@ -4093,11 +4195,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;
}
}
@@ -4106,7 +4208,7 @@
@Override
public String getAlwaysOnVpnPackage(int userId) {
- enforceConnectivityInternalPermission();
+ enforceControlAlwaysOnVpnPermission();
enforceCrossUserPermission(userId);
synchronized (mVpns) {
@@ -4120,6 +4222,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;
@@ -4348,7 +4480,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);
}
}
}
@@ -4900,8 +5032,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);
}
@@ -5894,12 +6026,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
@@ -5918,10 +6044,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
@@ -6182,7 +6314,7 @@
mKeepaliveTracker.startNattKeepalive(
getNetworkAgentInfoForNetwork(network),
intervalSeconds, messenger, binder,
- srcAddr, srcPort, dstAddr, ConnectivityManager.PacketKeepalive.NATT_PORT);
+ srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
}
@Override
@@ -6199,7 +6331,7 @@
@Override
public void stopKeepalive(Network network, int slot) {
mHandler.sendMessage(mHandler.obtainMessage(
- NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, slot, PacketKeepalive.SUCCESS, network));
+ NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network));
}
@Override
@@ -6228,7 +6360,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/DynamicAndroidService.java b/services/core/java/com/android/server/DynamicAndroidService.java
new file mode 100644
index 0000000..12a3f02
--- /dev/null
+++ b/services/core/java/com/android/server/DynamicAndroidService.java
@@ -0,0 +1,134 @@
+/*
+ * 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.content.Context;
+import android.content.pm.PackageManager;
+import android.gsi.GsiProgress;
+import android.gsi.IGsiService;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.IDynamicAndroidService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+/**
+ * DynamicAndroidService implements IDynamicAndroidService. It provides permission check before
+ * passing requests to gsid
+ */
+public class DynamicAndroidService extends IDynamicAndroidService.Stub implements DeathRecipient {
+ private static final String TAG = "DynamicAndroidService";
+ private static final String NO_SERVICE_ERROR = "no gsiservice";
+
+ private Context mContext;
+ private volatile IGsiService mGsiService;
+
+ DynamicAndroidService(Context context) {
+ mContext = context;
+ }
+
+ private static IGsiService connect(DeathRecipient recipient) throws RemoteException {
+ IBinder binder = ServiceManager.getService("gsiservice");
+ if (binder == null) {
+ throw new RemoteException(NO_SERVICE_ERROR);
+ }
+ /**
+ * The init will restart gsiservice if it crashed and the proxy object will need to be
+ * re-initialized in this case.
+ */
+ binder.linkToDeath(recipient, 0);
+ return IGsiService.Stub.asInterface(binder);
+ }
+
+ /** implements DeathRecipient */
+ @Override
+ public void binderDied() {
+ Slog.w(TAG, "gsiservice died; reconnecting");
+ synchronized (this) {
+ mGsiService = null;
+ }
+ }
+
+ private IGsiService getGsiService() throws RemoteException {
+ checkPermission();
+ synchronized (this) {
+ if (mGsiService == null) {
+ mGsiService = connect(this);
+ }
+ return mGsiService;
+ }
+ }
+
+ private void checkPermission() {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_DYNAMIC_ANDROID)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires MANAGE_DYNAMIC_ANDROID permission");
+ }
+ }
+
+ @Override
+ public boolean startInstallation(long systemSize, long userdataSize) throws RemoteException {
+ return getGsiService().startGsiInstall(systemSize, userdataSize, true) == 0;
+ }
+
+ @Override
+ public GsiProgress getInstallationProgress() throws RemoteException {
+ return getGsiService().getInstallProgress();
+ }
+
+ @Override
+ public boolean abort() throws RemoteException {
+ return getGsiService().cancelGsiInstall();
+ }
+
+ @Override
+ public boolean isInUse() throws RemoteException {
+ return getGsiService().isGsiRunning();
+ }
+
+ @Override
+ public boolean isInstalled() throws RemoteException {
+ return getGsiService().isGsiInstalled();
+ }
+
+ @Override
+ public boolean remove() throws RemoteException {
+ return getGsiService().removeGsiInstall();
+ }
+
+ @Override
+ public boolean toggle() throws RemoteException {
+ IGsiService gsiService = getGsiService();
+ if (gsiService.isGsiRunning()) {
+ return gsiService.disableGsiInstall();
+ } else {
+ return gsiService.setGsiBootable() == 0;
+ }
+ }
+
+ @Override
+ public boolean write(byte[] buf) throws RemoteException {
+ return getGsiService().commitGsiChunkFromMemory(buf);
+ }
+
+ @Override
+ public boolean commit() throws RemoteException {
+ return getGsiService().setGsiBootable() == 0;
+ }
+}
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..43af36f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,6 +52,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
import android.util.LocalLog;
import android.util.StatsLog;
@@ -206,9 +207,10 @@
private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
- private CallQuality mCallQuality;
+ private CallQuality mCallQuality = new CallQuality();
- private CallAttributes mCallAttributes;
+ private CallAttributes mCallAttributes = new CallAttributes(new PreciseCallState(),
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
private int[] mSrvccState;
@@ -226,6 +228,8 @@
private int mCallDisconnectCause = DisconnectCause.NOT_VALID;
+ private List<ImsReasonInfo> mImsReasonInfo = null;
+
private int mCallPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
private boolean mCarrierNetworkChangeState = false;
@@ -376,6 +380,7 @@
mCellLocation = new Bundle[numPhones];
mCellInfo = new ArrayList<List<CellInfo>>();
mSrvccState = new int[numPhones];
+ mImsReasonInfo = new ArrayList<ImsReasonInfo>();
mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
mEmergencyNumberList = new HashMap<>();
for (int i = 0; i < numPhones; i++) {
@@ -393,6 +398,7 @@
mCallForwarding[i] = false;
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
+ mImsReasonInfo.add(i, null);
mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
mPhysicalChannelConfigs.add(i, new ArrayList<PhysicalChannelConfig>());
}
@@ -738,6 +744,13 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
+ try {
+ r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(
@@ -1590,6 +1603,34 @@
}
}
+ public void notifyImsDisconnectCause(int subId, ImsReasonInfo imsReasonInfo) {
+ if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) {
+ return;
+ }
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ mImsReasonInfo.set(phoneId, imsReasonInfo);
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES)
+ && idMatch(r.subId, subId, phoneId)) {
+ try {
+ if (DBG_LOC) {
+ log("notifyImsCallDisconnectCause: mImsReasonInfo="
+ + imsReasonInfo + " r=" + r);
+ }
+ r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
public void notifyPreciseDataConnectionFailed(String apnType,
String apn, @DataFailCause.FailCause int failCause) {
if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
@@ -1626,7 +1667,7 @@
int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- mSrvccState[phoneId] = state;
+ mSrvccState[phoneId] = state;
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) &&
@@ -1837,6 +1878,7 @@
pw.println("mDataConnectionState=" + mDataConnectionState[i]);
pw.println("mCellLocation=" + mCellLocation[i]);
pw.println("mCellInfo=" + mCellInfo.get(i));
+ pw.println("mImsCallDisconnectCause=" + mImsReasonInfo.get(i).toString());
pw.decreaseIndent();
}
pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
@@ -2126,6 +2168,11 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
+ if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/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/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 1559ba8..d872e4d 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -16,26 +16,27 @@
package com.android.server.connectivity;
-// TODO: Clean up imports and remove references of PacketKeepalive constants.
-
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_INTERVAL;
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS;
-import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK;
-import static android.net.ConnectivityManager.PacketKeepalive.MIN_INTERVAL;
-import static android.net.ConnectivityManager.PacketKeepalive.NATT_PORT;
-import static android.net.ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
-import static android.net.ConnectivityManager.PacketKeepalive.SUCCESS;
-import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
-import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
+import static android.net.NattSocketKeepalive.NATT_PORT;
+import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
+import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
+import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
+import static android.net.SocketKeepalive.BINDER_DIED;
+import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
+import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
+import static android.net.SocketKeepalive.NO_KEEPALIVE;
+import static android.net.SocketKeepalive.SUCCESS;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.ConnectivityManager.PacketKeepalive;
import android.net.KeepalivePacketData;
+import android.net.NattKeepalivePacketData;
import android.net.NetworkAgent;
import android.net.NetworkUtils;
+import android.net.SocketKeepalive.InvalidPacketException;
import android.net.util.IpUtils;
import android.os.Binder;
import android.os.Handler;
@@ -60,7 +61,7 @@
import java.util.HashMap;
/**
- * Manages packet keepalive requests.
+ * Manages socket keepalive requests.
*
* Provides methods to stop and start keepalive requests, and keeps track of keepalives across all
* networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its
@@ -83,13 +84,13 @@
}
/**
- * Tracks information about a packet keepalive.
+ * Tracks information about a socket keepalive.
*
* All information about this keepalive is known at construction time except the slot number,
* which is only returned when the hardware has successfully started the keepalive.
*/
class KeepaliveInfo implements IBinder.DeathRecipient {
- // Bookkeping data.
+ // Bookkeeping data.
private final Messenger mMessenger;
private final IBinder mBinder;
private final int mUid;
@@ -98,7 +99,7 @@
/** Keepalive slot. A small integer that identifies this keepalive among the ones handled
* by this network. */
- private int mSlot = PacketKeepalive.NO_KEEPALIVE;
+ private int mSlot = NO_KEEPALIVE;
// Packet data.
private final KeepalivePacketData mPacket;
@@ -144,7 +145,7 @@
.toString();
}
- /** Sends a message back to the application via its PacketKeepalive.Callback. */
+ /** Sends a message back to the application via its SocketKeepalive.Callback. */
void notifyMessenger(int slot, int err) {
KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
}
@@ -153,8 +154,8 @@
public void binderDied() {
// Not called from ConnectivityService handler thread, so send it a message.
mConnectivityServiceHandler.obtainMessage(
- NetworkAgent.CMD_STOP_PACKET_KEEPALIVE,
- mSlot, PacketKeepalive.BINDER_DIED, mNai.network).sendToTarget();
+ NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE,
+ mSlot, BINDER_DIED, mNai.network).sendToTarget();
}
void unlinkDeathRecipient() {
@@ -181,7 +182,10 @@
}
private int checkInterval() {
- return mInterval >= MIN_INTERVAL ? SUCCESS : ERROR_INVALID_INTERVAL;
+ if (mInterval < MIN_INTERVAL_SEC || mInterval > MAX_INTERVAL_SEC) {
+ return ERROR_INVALID_INTERVAL;
+ }
+ return SUCCESS;
}
private int isValid() {
@@ -198,7 +202,7 @@
int error = isValid();
if (error == SUCCESS) {
Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
- mNai.asyncChannel.sendMessage(CMD_START_PACKET_KEEPALIVE, slot, mInterval, mPacket);
+ mNai.asyncChannel.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
} else {
handleStopKeepalive(mNai, mSlot, error);
return;
@@ -214,7 +218,7 @@
}
if (isStarted) {
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
- mNai.asyncChannel.sendMessage(CMD_STOP_PACKET_KEEPALIVE, mSlot);
+ mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
}
// TODO: at the moment we unconditionally return failure here. In cases where the
// NetworkAgent is alive, should we ask it to reply, so it can return failure?
@@ -225,7 +229,7 @@
void notifyMessenger(Messenger messenger, int slot, int err) {
Message message = Message.obtain();
- message.what = EVENT_PACKET_KEEPALIVE;
+ message.what = EVENT_SOCKET_KEEPALIVE;
message.arg1 = slot;
message.arg2 = err;
message.obj = null;
@@ -310,7 +314,7 @@
}
/** Handle keepalive events from lower layer. */
- public void handleEventPacketKeepalive(@NonNull NetworkAgentInfo nai,
+ public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai,
@NonNull Message message) {
int slot = message.arg1;
int reason = message.arg2;
@@ -369,16 +373,15 @@
KeepalivePacketData packet;
try {
- packet = KeepalivePacketData.nattKeepalivePacket(
+ packet = NattKeepalivePacketData.nattKeepalivePacket(
srcAddress, srcPort, dstAddress, NATT_PORT);
- } catch (KeepalivePacketData.InvalidPacketException e) {
+ } catch (InvalidPacketException e) {
notifyMessenger(messenger, NO_KEEPALIVE, e.error);
return;
}
KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds);
Log.d(TAG, "Created keepalive: " + ki.toString());
- mConnectivityServiceHandler.obtainMessage(
- NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget();
+ mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
}
/**
@@ -432,7 +435,7 @@
}
public void dump(IndentingPrintWriter pw) {
- pw.println("Packet keepalives:");
+ pw.println("Socket keepalives:");
pw.increaseIndent();
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
pw.println(nai.name());
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 9ea73fb..d0cff25 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -152,6 +152,10 @@
// Whether a captive portal was found during the last network validation attempt.
public boolean lastCaptivePortalDetected;
+ // Indicates the user was notified of a successful captive portal login since a portal was
+ // last detected.
+ public boolean captivePortalLoginNotified;
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
@@ -618,18 +622,19 @@
}
public String toString() {
- return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
- "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
- "lp{" + linkProperties + "} " +
- "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} " +
- "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} " +
- "created{" + created + "} lingering{" + isLingering() + "} " +
- "explicitlySelected{" + networkMisc.explicitlySelected + "} " +
- "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
- "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " +
- "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " +
- "clat{" + clatd + "} " +
- "}";
+ return "NetworkAgentInfo{ ni{" + networkInfo + "} "
+ + "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} "
+ + "lp{" + linkProperties + "} "
+ + "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} "
+ + "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} "
+ + "created{" + created + "} lingering{" + isLingering() + "} "
+ + "explicitlySelected{" + networkMisc.explicitlySelected + "} "
+ + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} "
+ + "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
+ + "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
+ + "captivePortalLoginNotified{" + captivePortalLoginNotified + "} "
+ + "clat{" + clatd + "} "
+ + "}";
}
public String name() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 36a2476..b50477b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -16,13 +16,16 @@
package com.android.server.connectivity;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.net.NetworkCapabilities;
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
@@ -31,15 +34,12 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.widget.Toast;
+
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
public class NetworkNotificationManager {
@@ -47,7 +47,8 @@
LOST_INTERNET(SystemMessage.NOTE_NETWORK_LOST_INTERNET),
NETWORK_SWITCH(SystemMessage.NOTE_NETWORK_SWITCH),
NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
- SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN);
+ SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
+ LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN);
public final int eventId;
@@ -192,6 +193,9 @@
details = r.getString(R.string.network_available_sign_in_detailed, name);
break;
}
+ } else if (notifyType == NotificationType.LOGGED_IN) {
+ title = WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID());
+ details = r.getString(R.string.captive_portal_logged_in_detailed);
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
String fromTransport = getTransportName(transportType);
String toTransport = getTransportName(getFirstTransportType(switchToNai));
@@ -239,6 +243,18 @@
}
}
+ /**
+ * Clear the notification with the given id, only if it matches the given type.
+ */
+ public void clearNotification(int id, NotificationType notifyType) {
+ final int previousEventId = mNotificationTypeMap.get(id);
+ final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
+ if (notifyType != previousNotifyType) {
+ return;
+ }
+ clearNotification(id);
+ }
+
public void clearNotification(int id) {
if (mNotificationTypeMap.indexOfKey(id) < 0) {
return;
@@ -290,6 +306,10 @@
return (t != null) ? t.name() : "UNKNOWN";
}
+ /**
+ * A notification with a higher number will take priority over a notification with a lower
+ * number.
+ */
private static int priority(NotificationType t) {
if (t == null) {
return 0;
@@ -302,6 +322,7 @@
case NETWORK_SWITCH:
return 2;
case LOST_INTERNET:
+ case LOGGED_IN:
return 1;
default:
return 0;
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/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
new file mode 100644
index 0000000..640504f
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -0,0 +1,330 @@
+/*
+ * 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.connectivity;
+
+import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
+import static android.net.SocketKeepalive.DATA_RECEIVED;
+import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_SOCKET_NOT_IDLE;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import static android.system.OsConstants.FIONREAD;
+import static android.system.OsConstants.IPPROTO_TCP;
+import static android.system.OsConstants.TIOCOUTQ;
+
+import android.annotation.NonNull;
+import android.net.NetworkUtils;
+import android.net.SocketKeepalive.InvalidSocketException;
+import android.net.TcpKeepalivePacketData.TcpSocketInfo;
+import android.net.TcpRepairWindow;
+import android.os.Handler;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Int32Ref;
+import android.system.Os;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+
+/**
+ * Manage tcp socket which offloads tcp keepalive.
+ *
+ * The input socket will be changed to repair mode and the application
+ * will not have permission to read/write data. If the application wants
+ * to write data, it must stop tcp keepalive offload to leave repair mode
+ * first. If a remote packet arrives, repair mode will be turned off and
+ * offload will be stopped. The application will receive a callback to know
+ * it can start reading data.
+ *
+ * {start,stop}SocketMonitor are thread-safe, but care must be taken in the
+ * order in which they are called. Please note that while calling
+ * {@link #startSocketMonitor(FileDescriptor, Messenger, int)} multiple times
+ * with either the same slot or the same FileDescriptor without stopping it in
+ * between will result in an exception, calling {@link #stopSocketMonitor(int)}
+ * multiple times with the same int is explicitly a no-op.
+ * Please also note that switching the socket to repair mode is not synchronized
+ * with either of these operations and has to be done in an orderly fashion
+ * with stopSocketMonitor. Take care in calling these in the right order.
+ * @hide
+ */
+public class TcpKeepaliveController {
+ private static final String TAG = "TcpKeepaliveController";
+ private static final boolean DBG = false;
+
+ private final MessageQueue mFdHandlerQueue;
+
+ private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
+
+ // Reference include/uapi/linux/tcp.h
+ private static final int TCP_REPAIR = 19;
+ private static final int TCP_REPAIR_QUEUE = 20;
+ private static final int TCP_QUEUE_SEQ = 21;
+ private static final int TCP_NO_QUEUE = 0;
+ private static final int TCP_RECV_QUEUE = 1;
+ private static final int TCP_SEND_QUEUE = 2;
+ private static final int TCP_REPAIR_OFF = 0;
+ private static final int TCP_REPAIR_ON = 1;
+ // Reference include/uapi/linux/sockios.h
+ private static final int SIOCINQ = FIONREAD;
+ private static final int SIOCOUTQ = TIOCOUTQ;
+
+ /**
+ * Keeps track of packet listeners.
+ * Key: slot number of keepalive offload.
+ * Value: {@link FileDescriptor} being listened to.
+ */
+ @GuardedBy("mListeners")
+ private final SparseArray<FileDescriptor> mListeners = new SparseArray<>();
+
+ public TcpKeepaliveController(final Handler connectivityServiceHandler) {
+ mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
+ }
+
+ /**
+ * Switch the tcp socket to repair mode and query tcp socket information.
+ *
+ * @param fd the fd of socket on which to use keepalive offload
+ * @return a {@link TcpKeepalivePacketData#TcpSocketInfo} object for current
+ * tcp/ip information.
+ */
+ // TODO : make this private. It's far too confusing that this gets called from outside
+ // at a time that nobody can understand, but the switch out is in this class only.
+ public static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
+ throws InvalidSocketException {
+ if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
+ final SocketAddress srcSockAddr;
+ final SocketAddress dstSockAddr;
+ final InetAddress srcAddress;
+ final InetAddress dstAddress;
+ final int srcPort;
+ final int dstPort;
+ int seq;
+ final int ack;
+ final TcpRepairWindow trw;
+
+ // Query source address and port.
+ try {
+ srcSockAddr = Os.getsockname(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Get sockname fail: ", e);
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
+ }
+ if (srcSockAddr instanceof InetSocketAddress) {
+ srcAddress = getAddress((InetSocketAddress) srcSockAddr);
+ srcPort = getPort((InetSocketAddress) srcSockAddr);
+ } else {
+ Log.e(TAG, "Invalid or mismatched SocketAddress");
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET);
+ }
+ // Query destination address and port.
+ try {
+ dstSockAddr = Os.getpeername(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Get peername fail: ", e);
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
+ }
+ if (dstSockAddr instanceof InetSocketAddress) {
+ dstAddress = getAddress((InetSocketAddress) dstSockAddr);
+ dstPort = getPort((InetSocketAddress) dstSockAddr);
+ } else {
+ Log.e(TAG, "Invalid or mismatched peer SocketAddress");
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET);
+ }
+
+ // Query sequence and ack number
+ dropAllIncomingPackets(fd, true);
+ try {
+ // Enter tcp repair mode.
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
+ // Check if socket is idle.
+ if (!isSocketIdle(fd)) {
+ throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
+ }
+ // Query write sequence number from SEND_QUEUE.
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
+ seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ // Query read sequence number from RECV_QUEUE.
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
+ ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ // Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
+ // Finally, check if socket is still idle. TODO : this check needs to move to
+ // after starting polling to prevent a race.
+ if (!isSocketIdle(fd)) {
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET);
+ }
+
+ // Query tcp window size.
+ trw = NetworkUtils.getTcpRepairWindow(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Exception reading TCP state from socket", e);
+ try {
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+ } catch (ErrnoException ex) {
+ Log.e(TAG, "Exception while turning off repair mode due to exception", ex);
+ }
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
+ } finally {
+ dropAllIncomingPackets(fd, false);
+ }
+
+ // Keepalive sequence number is last sequence number - 1. If it couldn't be retrieved,
+ // then it must be set to -1, so decrement in all cases.
+ seq = seq - 1;
+
+ return new TcpSocketInfo(srcAddress, srcPort, dstAddress, dstPort, seq, ack, trw.rcvWnd,
+ trw.rcvWndScale);
+ }
+
+ private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
+ throws ErrnoException {
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+ }
+
+ /**
+ * Start monitoring incoming packets.
+ *
+ * @param fd socket fd to monitor.
+ * @param messenger a callback to notify socket status.
+ * @param slot keepalive slot.
+ */
+ public void startSocketMonitor(@NonNull final FileDescriptor fd,
+ @NonNull final Messenger messenger, final int slot) {
+ synchronized (mListeners) {
+ if (null != mListeners.get(slot)) {
+ throw new IllegalArgumentException("This slot is already taken");
+ }
+ for (int i = 0; i < mListeners.size(); ++i) {
+ if (fd.equals(mListeners.valueAt(i))) {
+ throw new IllegalArgumentException("This fd is already registered");
+ }
+ }
+ mFdHandlerQueue.addOnFileDescriptorEventListener(fd, FD_EVENTS, (readyFd, events) -> {
+ // This can't be called twice because the queue guarantees that once the listener
+ // is unregistered it can't be called again, even for a message that arrived
+ // before it was unregistered.
+ int result;
+ try {
+ // First move the socket out of repair mode.
+ if (DBG) Log.d(TAG, "Moving socket out of repair mode for event : " + readyFd);
+ switchOutOfRepairMode(readyFd);
+ result = (0 != (events & EVENT_ERROR)) ? ERROR_INVALID_SOCKET : DATA_RECEIVED;
+ } catch (ErrnoException e) {
+ // Could not move the socket out of repair mode. Still continue with notifying
+ // the client
+ Log.e(TAG, "Cannot switch socket out of repair mode", e);
+ result = ERROR_INVALID_SOCKET;
+ }
+ // Prepare and send the message to the receiver.
+ final Message message = Message.obtain();
+ message.what = EVENT_SOCKET_KEEPALIVE;
+ message.arg1 = slot;
+ message.arg2 = result;
+ try {
+ messenger.send(message);
+ } catch (RemoteException e) {
+ // Remote process died
+ }
+ synchronized (mListeners) {
+ mListeners.remove(slot);
+ }
+ // The listener returns the new set of events to listen to. Because 0 means no
+ // event, the listener gets unregistered.
+ return 0;
+ });
+ mListeners.put(slot, fd);
+ }
+ }
+
+ /** Stop socket monitor */
+ // This slot may have been stopped automatically already because the socket received data,
+ // was closed on the other end or otherwise suffered some error. In this case, this function
+ // is a no-op.
+ public void stopSocketMonitor(final int slot) {
+ final FileDescriptor fd;
+ synchronized (mListeners) {
+ fd = mListeners.get(slot);
+ if (null == fd) return;
+ mListeners.remove(slot);
+ }
+ mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
+ try {
+ if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
+ switchOutOfRepairMode(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Cannot switch socket out of repair mode", e);
+ // Well, there is not much to do here to recover
+ }
+ }
+
+ private static InetAddress getAddress(InetSocketAddress inetAddr) {
+ return inetAddr.getAddress();
+ }
+
+ private static int getPort(InetSocketAddress inetAddr) {
+ return inetAddr.getPort();
+ }
+
+ private static boolean isSocketIdle(FileDescriptor fd) throws ErrnoException {
+ return isReceiveQueueEmpty(fd) && isSendQueueEmpty(fd);
+ }
+
+ private static boolean isReceiveQueueEmpty(FileDescriptor fd)
+ throws ErrnoException {
+ Int32Ref result = new Int32Ref(-1);
+ Os.ioctlInt(fd, SIOCINQ, result);
+ if (result.value != 0) {
+ Log.e(TAG, "Read queue has data");
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isSendQueueEmpty(FileDescriptor fd)
+ throws ErrnoException {
+ Int32Ref result = new Int32Ref(-1);
+ Os.ioctlInt(fd, SIOCOUTQ, result);
+ if (result.value != 0) {
+ Log.e(TAG, "Write queue has data");
+ return false;
+ }
+ return true;
+ }
+
+ private static void dropAllIncomingPackets(FileDescriptor fd, boolean enable)
+ throws InvalidSocketException {
+ try {
+ if (enable) {
+ NetworkUtils.attachDropAllBPFFilter(fd);
+ } else {
+ NetworkUtils.detachBPFFilter(fd);
+ }
+ } catch (SocketException e) {
+ Log.e(TAG, "Socket Exception: ", e);
+ throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index eb5be77..a14fd17 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -121,7 +121,6 @@
import java.util.HashSet;
import java.util.Set;
-
/**
* @hide
*
@@ -223,7 +222,8 @@
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
- mEntitlementMgr = mDeps.getEntitlementManager(mContext, mLog, systemProperties);
+ mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM,
+ mLog, systemProperties);
mCarrierConfigChange = new VersionedBroadcastListener(
"CarrierConfigChangeListener", mContext, smHandler, filter,
(Intent ignored) -> {
@@ -470,6 +470,7 @@
} else {
sendTetherResult(receiver, resultCode);
}
+ mEntitlementMgr.updateEntitlementCacheValue(type, resultCode);
}
};
@@ -1662,6 +1663,14 @@
mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest());
}
+ /** Get the latest value of the tethering entitlement check. */
+ public void getLatestTetheringEntitlementValue(int type, ResultReceiver receiver,
+ boolean showEntitlementUi) {
+ if (receiver != null) {
+ mEntitlementMgr.getLatestTetheringEntitlementValue(type, receiver, showEntitlementUi);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
// Binder.java closes the resource for us.
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c72c9dd..9141ccb 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
@@ -165,6 +165,7 @@
private final NetworkInfo mNetworkInfo;
private String mPackage;
private int mOwnerUID;
+ private boolean mIsPackageTargetingAtLeastQ;
private String mInterface;
private Connection mConnection;
private LegacyVpnRunner mLegacyVpnRunner;
@@ -194,6 +195,12 @@
private boolean mLockdown = false;
/**
+ * Set of packages in addition to the VPN app itself that can access the network directly when
+ * VPN is not connected even if {@code mLockdown} is set.
+ */
+ private @NonNull List<String> mLockdownWhitelist = Collections.emptyList();
+
+ /**
* List of UIDs for which networking should be blocked until VPN is ready, during brief periods
* when VPN is not running. For example, during system startup or after a crash.
* @see mLockdown
@@ -220,6 +227,7 @@
mPackage = VpnConfig.LEGACY_VPN;
mOwnerUID = getAppUid(mPackage, mUserHandle);
+ mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
try {
netService.registerObserver(mObserver);
@@ -261,8 +269,11 @@
public void updateCapabilities() {
final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
+ // Only apps targeting Q and above can explicitly declare themselves as metered.
+ final boolean isAlwaysMetered =
+ mIsPackageTargetingAtLeastQ && (mConfig == null || mConfig.isMetered);
updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
- mNetworkCapabilities);
+ mNetworkCapabilities, isAlwaysMetered);
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
@@ -271,11 +282,13 @@
@VisibleForTesting
public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
- NetworkCapabilities caps) {
+ NetworkCapabilities caps, boolean isAlwaysMetered) {
int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- boolean metered = false;
+ // VPN's meteredness is OR'd with isAlwaysMetered and meteredness of its underlying
+ // networks.
+ boolean metered = isAlwaysMetered;
boolean roaming = false;
boolean congested = false;
@@ -320,9 +333,9 @@
*
* Used to enable/disable legacy VPN lockdown.
*
- * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
- * previous settings from calling that function will be replaced and saved with the
- * always-on state.
+ * This uses the same ip rule mechanism as
+ * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
+ * that function will be replaced and saved with the always-on state.
*
* @param lockdown whether to prevent all traffic outside of a VPN.
*/
@@ -419,12 +432,14 @@
*
* @param packageName the package to designate as always-on VPN supplier.
* @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+ * @param lockdownWhitelist packages to be whitelisted from lockdown.
* @return {@code true} if the package has been set as always-on, {@code false} otherwise.
*/
- public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
+ public synchronized boolean setAlwaysOnPackage(
+ String packageName, boolean lockdown, List<String> lockdownWhitelist) {
enforceControlPermissionOrInternalCaller();
- if (setAlwaysOnPackageInternal(packageName, lockdown)) {
+ if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) {
saveAlwaysOnPackage();
return true;
}
@@ -439,15 +454,27 @@
*
* @param packageName the package to designate as always-on VPN supplier.
* @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+ * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if
+ * {@code lockdown} is {@code true}. Packages must not contain commas.
* @return {@code true} if the package has been set as always-on, {@code false} otherwise.
*/
@GuardedBy("this")
- private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
+ private boolean setAlwaysOnPackageInternal(
+ String packageName, boolean lockdown, List<String> lockdownWhitelist) {
if (VpnConfig.LEGACY_VPN.equals(packageName)) {
Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
return false;
}
+ if (lockdownWhitelist != null) {
+ for (String pkg : lockdownWhitelist) {
+ if (pkg.contains(",")) {
+ Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg);
+ return false;
+ }
+ }
+ }
+
if (packageName != null) {
// Pre-authorize new always-on VPN package.
if (!setPackageAuthorization(packageName, true)) {
@@ -460,13 +487,18 @@
}
mLockdown = (mAlwaysOn && lockdown);
+ mLockdownWhitelist = (mLockdown && lockdownWhitelist != null)
+ ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist))
+ : Collections.emptyList();
+
if (isCurrentPreparedPackage(packageName)) {
updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
+ setVpnForcedLocked(mLockdown);
} else {
// Prepare this app. The notification will update as a side-effect of updateState().
+ // It also calls setVpnForcedLocked().
prepareInternal(packageName);
}
- setVpnForcedLocked(mLockdown);
return true;
}
@@ -478,7 +510,6 @@
* @return the package name of the VPN controller responsible for always-on VPN,
* or {@code null} if none is set or always-on VPN is controlled through
* lockdown instead.
- * @hide
*/
public synchronized String getAlwaysOnPackage() {
enforceControlPermissionOrInternalCaller();
@@ -486,6 +517,13 @@
}
/**
+ * @return an immutable list of packages whitelisted from always-on VPN lockdown.
+ */
+ public synchronized List<String> getLockdownWhitelist() {
+ return mLockdown ? mLockdownWhitelist : null;
+ }
+
+ /**
* Save the always-on package and lockdown config into Settings.Secure
*/
@GuardedBy("this")
@@ -496,6 +534,9 @@
getAlwaysOnPackage(), mUserHandle);
mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
(mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
+ mSystemServices.settingsSecurePutStringForUser(
+ Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
+ String.join(",", mLockdownWhitelist), mUserHandle);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -512,7 +553,11 @@
Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
- setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
+ final String whitelistString = mSystemServices.settingsSecureGetStringForUser(
+ Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle);
+ final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString)
+ ? Collections.emptyList() : Arrays.asList(whitelistString.split(","));
+ setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -532,7 +577,7 @@
}
// Remove always-on VPN if it's not supported.
if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
- setAlwaysOnPackage(null, false);
+ setAlwaysOnPackage(null, false, null);
return false;
}
// Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -686,6 +731,7 @@
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
mOwnerUID = getAppUid(newPackage, mUserHandle);
+ mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
try {
mNetd.allowProtect(mOwnerUID);
} catch (Exception e) {
@@ -751,6 +797,21 @@
return result;
}
+ private boolean doesPackageTargetAtLeastQ(String packageName) {
+ if (VpnConfig.LEGACY_VPN.equals(packageName)) {
+ return true;
+ }
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ ApplicationInfo appInfo =
+ pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
+ return appInfo.targetSdkVersion >= VERSION_CODES.Q;
+ } catch (NameNotFoundException unused) {
+ Log.w(TAG, "Can't find \"" + packageName + "\"");
+ return false;
+ }
+ }
+
public NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}
@@ -793,6 +854,8 @@
}
}
+ lp.setHttpProxy(mConfig.proxyInfo);
+
if (!allowIPv4) {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
}
@@ -1036,6 +1099,8 @@
// as rules are deleted. This prevents data leakage as the rules are moved over.
agentDisconnect(oldNetworkAgent);
}
+ // Set up VPN's capabilities such as meteredness.
+ updateCapabilities();
if (oldConnection != null) {
mContext.unbindService(oldConnection);
@@ -1247,9 +1312,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 +1331,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();
@@ -1730,6 +1801,7 @@
config.user = profile.key;
config.interfaze = iface;
config.session = profile.name;
+ config.isMetered = false;
config.addLegacyRoutes(profile.routes);
if (!profile.dnsServers.isEmpty()) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index a4e3e1d..75aac10 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -21,6 +21,9 @@
import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import static com.android.internal.R.string.config_wifi_tether_enable;
@@ -31,15 +34,21 @@
import android.content.res.Resources;
import android.net.util.SharedLog;
import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
/**
@@ -50,6 +59,7 @@
*/
public class EntitlementManager {
private static final String TAG = EntitlementManager.class.getSimpleName();
+ private static final boolean DBG = false;
// {@link ComponentName} of the Service used to run tether provisioning.
private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
@@ -65,15 +75,19 @@
private final Context mContext;
private final MockableSystemProperties mSystemProperties;
private final SharedLog mLog;
+ private final Handler mMasterHandler;
+ private final SparseIntArray mEntitlementCacheValue;
@Nullable
private TetheringConfiguration mConfig;
- public EntitlementManager(Context ctx, SharedLog log,
+ public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
MockableSystemProperties systemProperties) {
mContext = ctx;
- mLog = log;
+ mLog = log.forSubComponent(TAG);
mCurrentTethers = new ArraySet<Integer>();
mSystemProperties = systemProperties;
+ mEntitlementCacheValue = new SparseIntArray();
+ mMasterHandler = tetherMasterSM.getHandler();
}
/**
@@ -128,6 +142,10 @@
* Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
*/
public void reevaluateSimCardProvisioning() {
+ synchronized (mEntitlementCacheValue) {
+ mEntitlementCacheValue.clear();
+ }
+
if (!mConfig.hasMobileHotspotProvisionApp()) return;
if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
@@ -175,6 +193,11 @@
}
public void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+ runUiTetherProvisioning(type, receiver);
+ }
+
+ @VisibleForTesting
+ protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
@@ -221,4 +244,70 @@
Binder.restoreCallingIdentity(ident);
}
}
+
+ private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
+ ResultReceiver rr = new ResultReceiver(mMasterHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
+ receiver.send(updatedCacheValue, null);
+ }
+ };
+
+ return writeToParcel(rr);
+ }
+
+ private ResultReceiver writeToParcel(final ResultReceiver receiver) {
+ // This is necessary to avoid unmarshalling issues when sending the receiver
+ // across processes.
+ Parcel parcel = Parcel.obtain();
+ receiver.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+ return receiverForSending;
+ }
+
+ /**
+ * Update the last entitlement value to internal cache
+ *
+ * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+ * @param resultCode last entitlement value
+ * @return the last updated entitlement value
+ */
+ public int updateEntitlementCacheValue(int type, int resultCode) {
+ if (DBG) {
+ Log.d(TAG, "updateEntitlementCacheValue: " + type + ", result: " + resultCode);
+ }
+ synchronized (mEntitlementCacheValue) {
+ if (resultCode == TETHER_ERROR_NO_ERROR) {
+ mEntitlementCacheValue.put(type, resultCode);
+ return resultCode;
+ } else {
+ mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
+ return TETHER_ERROR_PROVISION_FAILED;
+ }
+ }
+ }
+
+ /** Get the last value of the tethering entitlement check. */
+ public void getLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
+ boolean showEntitlementUi) {
+ if (!isTetherProvisioningRequired()) {
+ receiver.send(TETHER_ERROR_NO_ERROR, null);
+ return;
+ }
+
+ final int cacheValue;
+ synchronized (mEntitlementCacheValue) {
+ cacheValue = mEntitlementCacheValue.get(
+ downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
+ }
+ if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
+ receiver.send(cacheValue, null);
+ } else {
+ ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
+ runUiTetherProvisioning(downstream, proxy);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index a42efe9..6d6f81e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -81,8 +81,8 @@
/**
* Get a reference to the EntitlementManager to be used by tethering.
*/
- public EntitlementManager getEntitlementManager(Context ctx, SharedLog log,
- MockableSystemProperties systemProperties) {
- return new EntitlementManager(ctx, log, systemProperties);
+ public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
+ SharedLog log, MockableSystemProperties systemProperties) {
+ return new EntitlementManager(ctx, target, log, systemProperties);
}
}
diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS
index 3c9bbf8..426f002 100644
--- a/services/core/java/com/android/server/dreams/OWNERS
+++ b/services/core/java/com/android/server/dreams/OWNERS
@@ -1,3 +1,3 @@
-dsandler@google.com
+dsandler@android.com
michaelwr@google.com
roosa@google.com
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 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/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index f736056..1dada92 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -17,8 +17,10 @@
package com.android.server.os;
import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.BugreportParams;
import android.os.IDumpstate;
@@ -28,26 +30,29 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserManager;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
import java.io.FileDescriptor;
// TODO(b/111441001):
-// 1. Handle the case where another bugreport is in progress
-// 2. Make everything threadsafe
-// 3. Pass validation & other errors on listener
+// Intercept onFinished() & implement death recipient here and shutdown
+// bugreportd service.
/**
* Implementation of the service that provides a privileged API to capture and consume bugreports.
*
- * <p>Delegates the actualy generation to a native implementation of {@code Dumpstate}.
+ * <p>Delegates the actualy generation to a native implementation of {@code IDumpstate}.
*/
class BugreportManagerServiceImpl extends IDumpstate.Stub {
private static final String TAG = "BugreportManagerService";
private static final String BUGREPORT_SERVICE = "bugreportd";
private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
- private IDumpstate mDs = null;
+ private final Object mLock = new Object();
private final Context mContext;
private final AppOpsManager mAppOps;
@@ -59,43 +64,44 @@
@Override
@RequiresPermission(android.Manifest.permission.DUMP)
public IDumpstateToken setListener(String name, IDumpstateListener listener,
- boolean getSectionDetails) throws RemoteException {
- // TODO(b/111441001): Figure out if lazy setting of listener should be allowed
- // and if so how to handle it.
+ boolean getSectionDetails) {
throw new UnsupportedOperationException("setListener is not allowed on this service");
}
- // TODO(b/111441001): Intercept onFinished here in system server and shutdown
- // the bugreportd service.
@Override
@RequiresPermission(android.Manifest.permission.DUMP)
public void startBugreport(int callingUidUnused, String callingPackage,
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
- int bugreportMode, IDumpstateListener listener) throws RemoteException {
- int callingUid = Binder.getCallingUid();
- // TODO(b/111441001): validate all arguments & ensure primary user
- validate(bugreportMode);
+ int bugreportMode, IDumpstateListener listener) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+ Preconditions.checkNotNull(callingPackage);
+ Preconditions.checkNotNull(bugreportFd);
+ Preconditions.checkNotNull(listener);
+ validateBugreportMode(bugreportMode);
+ ensureIsPrimaryUser();
+ int callingUid = Binder.getCallingUid();
mAppOps.checkPackage(callingUid, callingPackage);
- mDs = getDumpstateService();
- if (mDs == null) {
- Slog.w(TAG, "Unable to get bugreport service");
- // TODO(b/111441001): pass error on listener
- return;
+
+ synchronized (mLock) {
+ startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
+ bugreportMode, listener);
}
- mDs.startBugreport(callingUid, callingPackage,
- bugreportFd, screenshotFd, bugreportMode, listener);
}
@Override
@RequiresPermission(android.Manifest.permission.DUMP)
- public void cancelBugreport() throws RemoteException {
- // This tells init to cancel bugreportd service.
- SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
- mDs = null;
+ public void cancelBugreport() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
+ // This tells init to cancel bugreportd service. Note that this is achieved through setting
+ // a system property which is not thread-safe. So the lock here offers thread-safety only
+ // among callers of the API.
+ synchronized (mLock) {
+ SystemProperties.set("ctl.stop", BUGREPORT_SERVICE);
+ }
}
- private boolean validate(@BugreportParams.BugreportMode int mode) {
+ private void validateBugreportMode(@BugreportParams.BugreportMode int mode) {
if (mode != BugreportParams.BUGREPORT_MODE_FULL
&& mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
&& mode != BugreportParams.BUGREPORT_MODE_REMOTE
@@ -103,9 +109,66 @@
&& mode != BugreportParams.BUGREPORT_MODE_TELEPHONY
&& mode != BugreportParams.BUGREPORT_MODE_WIFI) {
Slog.w(TAG, "Unknown bugreport mode: " + mode);
- return false;
+ throw new IllegalArgumentException("Unknown bugreport mode: " + mode);
}
- return true;
+ }
+
+ /**
+ * Validates that the current user is the primary user.
+ *
+ * @throws IllegalArgumentException if the current user is not the primary user
+ */
+ private void ensureIsPrimaryUser() {
+ UserInfo currentUser = null;
+ try {
+ currentUser = ActivityManager.getService().getCurrentUser();
+ } catch (RemoteException e) {
+ // Impossible to get RemoteException for an in-process call.
+ }
+
+ UserInfo primaryUser = UserManager.get(mContext).getPrimaryUser();
+ if (currentUser == null) {
+ logAndThrow("No current user. Only primary user is allowed to take bugreports.");
+ }
+ if (primaryUser == null) {
+ logAndThrow("No primary user. Only primary user is allowed to take bugreports.");
+ }
+ if (primaryUser.id != currentUser.id) {
+ logAndThrow("Current user not primary user. Only primary user"
+ + " is allowed to take bugreports.");
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void startBugreportLocked(int callingUid, String callingPackage,
+ FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+ int bugreportMode, IDumpstateListener listener) {
+ if (isDumpstateBinderServiceRunningLocked()) {
+ Slog.w(TAG, "'dumpstate' is already running. Cannot start a new bugreport"
+ + " while another one is currently in progress.");
+ // TODO(b/111441001): Use a new error code; add this to the documentation of the API.
+ reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+ return;
+ }
+
+ IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
+ if (ds == null) {
+ Slog.w(TAG, "Unable to get bugreport service");
+ reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+ return;
+ }
+ try {
+ ds.startBugreport(callingUid, callingPackage,
+ bugreportFd, screenshotFd, bugreportMode, listener);
+ } catch (RemoteException e) {
+ reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean isDumpstateBinderServiceRunningLocked() {
+ IDumpstate ds = IDumpstate.Stub.asInterface(ServiceManager.getService("dumpstate"));
+ return ds != null;
}
/*
@@ -115,8 +178,12 @@
* <p>Generating bugreports requires root privileges. To limit the footprint
* of the root access, the actual generation in Dumpstate binary is accessed as a
* oneshot service 'bugreport'.
+ *
+ * <p>Note that starting the service is achieved through setting a system property, which is
+ * not thread-safe. So the lock here offers thread-safety only among callers of the API.
*/
- private IDumpstate getDumpstateService() {
+ @GuardedBy("mLock")
+ private IDumpstate startAndGetDumpstateBinderServiceLocked() {
// Start bugreport service.
SystemProperties.set("ctl.start", BUGREPORT_SERVICE);
@@ -145,4 +212,18 @@
}
return ds;
}
+
+ private void reportError(IDumpstateListener listener, int errorCode) {
+ try {
+ listener.onError(errorCode);
+ } catch (RemoteException e) {
+ // Something went wrong in binder or app process. There's nothing to do here.
+ Slog.w(TAG, "onError() transaction threw RemoteException: " + e.getMessage());
+ }
+ }
+
+ private void logAndThrow(String message) {
+ Slog.w(TAG, message);
+ throw new IllegalArgumentException(message);
+ }
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 60d7925..33b8641 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -51,6 +51,8 @@
per-file UserManagerService.java = yamasani@google.com
per-file UserRestrictionsUtils.java = omakoto@google.com
per-file UserRestrictionsUtils.java = yamasani@google.com
+per-file UserRestrictionsUtils.java = rubinxu@google.com
+per-file UserRestrictionsUtils.java = sandness@google.com
# security
per-file KeySetHandle.java = cbrubaker@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 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..a8be07d7 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/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
old mode 100644
new mode 100755
index c1607e9..f08e585
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
@@ -46,7 +45,6 @@
import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
-import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -56,7 +54,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
import android.view.Surface;
import com.android.internal.util.DumpUtils;
@@ -943,7 +940,7 @@
sinkChannelMask = sinkConfig.channelMask();
}
if (sinkFormat == AudioFormat.ENCODING_DEFAULT) {
- sinkChannelMask = sinkConfig.format();
+ sinkFormat = sinkConfig.format();
}
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 5f2a0e8..6735ab4 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -120,6 +120,7 @@
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.system.suspend@1.0",
+ "suspend_control_aidl_interface-cpp",
],
static_libs: [
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 0ff60e4..8f6cafb 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -30,8 +30,8 @@
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
-#include <android/system/suspend/1.0/ISystemSuspend.h>
-#include <android/system/suspend/1.0/ISystemSuspendCallback.h>
+#include <android/system/suspend/BnSuspendCallback.h>
+#include <android/system/suspend/ISuspendControlService.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -44,14 +44,14 @@
using android::hardware::Return;
using android::hardware::Void;
+using android::system::suspend::BnSuspendCallback;
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
using android::hardware::power::V1_0::Status;
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
-using android::system::suspend::V1_0::ISystemSuspend;
-using android::system::suspend::V1_0::ISystemSuspendCallback;
+using android::system::suspend::ISuspendControlService;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -66,7 +66,7 @@
extern sp<IPowerV1_0> getPowerHalV1_0();
extern sp<IPowerV1_1> getPowerHalV1_1();
extern bool processPowerHalReturn(const Return<void> &ret, const char* functionName);
-extern sp<ISystemSuspend> getSuspendHal();
+extern sp<ISuspendControlService> getSuspendControl();
// Java methods used in getLowPowerStats
static jmethodID jgetAndUpdatePlatformState = NULL;
@@ -74,17 +74,17 @@
static jmethodID jputVoter = NULL;
static jmethodID jputState = NULL;
-class WakeupCallback : public ISystemSuspendCallback {
-public:
- Return<void> notifyWakeup(bool success) override {
- ALOGV("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
+class WakeupCallback : public BnSuspendCallback {
+ public:
+ binder::Status notifyWakeup(bool success) override {
+ ALOGI("In wakeup_callback: %s", success ? "resumed from suspend" : "suspend aborted");
int ret = sem_post(&wakeup_sem);
if (ret < 0) {
char buf[80];
strerror_r(errno, buf, sizeof(buf));
ALOGE("Error posting wakeup sem: %s\n", buf);
}
- return Void();
+ return binder::Status::ok();
}
};
@@ -107,9 +107,12 @@
jniThrowException(env, "java/lang/IllegalStateException", buf);
return -1;
}
- ALOGV("Registering callback...");
- sp<ISystemSuspend> suspendHal = getSuspendHal();
- suspendHal->registerCallback(new WakeupCallback());
+ sp<ISuspendControlService> suspendControl = getSuspendControl();
+ bool isRegistered = false;
+ suspendControl->registerCallback(new WakeupCallback(), &isRegistered);
+ if (!isRegistered) {
+ ALOGE("Failed to register wakeup callback");
+ }
}
// Wait for wakeup.
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/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 0c9b5f4..9be728b 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -20,6 +20,7 @@
#include <android/hardware/power/1.1/IPower.h>
#include <android/system/suspend/1.0/ISystemSuspend.h>
+#include <android/system/suspend/ISuspendControlService.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
@@ -30,13 +31,14 @@
#include <android-base/chrono_utils.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <binder/IServiceManager.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <hidl/ServiceManagement.h>
#include <utils/Timers.h>
#include <utils/misc.h>
#include <utils/String8.h>
#include <utils/Log.h>
-#include <hardware/power.h>
-#include <hardware_legacy/power.h>
-#include <hidl/ServiceManagement.h>
#include "com_android_server_power_PowerManagerService.h"
@@ -48,6 +50,7 @@
using android::system::suspend::V1_0::ISystemSuspend;
using android::system::suspend::V1_0::IWakeLock;
using android::system::suspend::V1_0::WakeLockType;
+using android::system::suspend::ISuspendControlService;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
@@ -176,6 +179,7 @@
}
static sp<ISystemSuspend> gSuspendHal = nullptr;
+static sp<ISuspendControlService> gSuspendControl = nullptr;
static sp<IWakeLock> gSuspendBlocker = nullptr;
static std::mutex gSuspendMutex;
@@ -191,18 +195,33 @@
return gSuspendHal;
}
+sp<ISuspendControlService> getSuspendControl() {
+ static std::once_flag suspendControlFlag;
+ std::call_once(suspendControlFlag, [](){
+ while(gSuspendControl == nullptr) {
+ sp<IBinder> control =
+ defaultServiceManager()->getService(String16("suspend_control"));
+ if (control != nullptr) {
+ gSuspendControl = interface_cast<ISuspendControlService>(control);
+ }
+ }
+ });
+ return gSuspendControl;
+}
+
void enableAutoSuspend() {
static bool enabled = false;
-
- std::lock_guard<std::mutex> lock(gSuspendMutex);
if (!enabled) {
- sp<ISystemSuspend> suspendHal = getSuspendHal();
- suspendHal->enableAutosuspend();
- enabled = true;
+ sp<ISuspendControlService> suspendControl = getSuspendControl();
+ suspendControl->enableAutosuspend(&enabled);
}
- if (gSuspendBlocker) {
- gSuspendBlocker->release();
- gSuspendBlocker.clear();
+
+ {
+ std::lock_guard<std::mutex> lock(gSuspendMutex);
+ if (gSuspendBlocker) {
+ gSuspendBlocker->release();
+ gSuspendBlocker.clear();
+ }
}
}
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3ecbd47..75cd82e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -758,6 +758,7 @@
private void startOtherServices() {
final Context context = mSystemContext;
VibratorService vibrator = null;
+ DynamicAndroidService dynamicAndroid = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
IpSecService ipSecService = null;
@@ -867,6 +868,11 @@
ServiceManager.addService("vibrator", vibrator);
traceEnd();
+ traceBeginAndSlog("StartDynamicAndroidService");
+ dynamicAndroid = new DynamicAndroidService(context);
+ ServiceManager.addService("dynamic_android", dynamicAndroid);
+ traceEnd();
+
if (!isWatch) {
traceBeginAndSlog("StartConsumerIrService");
consumerIr = new ConsumerIrService(context);
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/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/services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java
new file mode 100644
index 0000000..1494284
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/DynamicAndroidServiceTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.os.IDynamicAndroidService;
+import android.os.ServiceManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class DynamicAndroidServiceTest extends AndroidTestCase {
+ private static final String TAG = "DynamicAndroidServiceTests";
+ private IDynamicAndroidService mService;
+
+ @Override
+ protected void setUp() throws Exception {
+ mService =
+ IDynamicAndroidService.Stub.asInterface(
+ ServiceManager.getService("dynamic_android"));
+ }
+
+ @LargeTest
+ public void test1() {
+ assertTrue("dynamic_android service available", mService != null);
+ try {
+ mService.startInstallation(1 << 20, 8 << 30);
+ fail("DynamicAndroidService did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ } catch (Exception e) {
+ fail(e.toString());
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 8461166..39fc715 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -124,6 +124,7 @@
static class MyInjector extends AppStandbyController.Injector {
long mElapsedRealtime;
+ boolean mIsAppIdleEnabled = true;
boolean mIsCharging;
List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
boolean mDisplayOn;
@@ -155,7 +156,7 @@
@Override
boolean isAppIdleEnabled() {
- return true;
+ return mIsAppIdleEnabled;
}
@Override
@@ -266,6 +267,13 @@
}
}
+ private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
+ mInjector.mIsAppIdleEnabled = enabled;
+ if (controller != null) {
+ controller.setAppIdleEnabled(enabled);
+ }
+ }
+
private AppStandbyController setupController() throws Exception {
mInjector.mElapsedRealtime = 0;
setupPm(mInjector.getContext().getPackageManager());
@@ -335,7 +343,7 @@
public void onParoleStateChanged(boolean isParoleOn) {
synchronized (this) {
// Only record information if it is being looked for
- if (mLatch.getCount() > 0) {
+ if (mLatch != null && mLatch.getCount() > 0) {
mOnParole = isParoleOn;
mLastParoleChangeTime = getCurrentTime();
mLatch.countDown();
@@ -396,6 +404,74 @@
marginOfError);
}
+ @Test
+ public void testEnabledState() throws Exception {
+ TestParoleListener paroleListener = new TestParoleListener();
+ mController.addListener(paroleListener);
+ long lastUpdateTime;
+
+ // Test that listeners are notified if enabled changes when the device is not in parole.
+ setChargingState(mController, false);
+
+ // Start off not enabled. Device is effectively on permanent parole.
+ setAppIdleEnabled(mController, false);
+
+ // Enable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertFalse(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ // Disable controller
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ // Make sure AppStandbyController doesn't notify listeners when there's no change.
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+
+ // Test that listeners aren't notified if enabled status changes when the device is already
+ // in parole.
+
+ // A device is in parole whenever it's charging.
+ setChargingState(mController, true);
+
+ // Start off not enabled.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ lastUpdateTime = paroleListener.getLastParoleChangeTime();
+
+ // Test that toggling doesn't notify the listener.
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, true);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+
+ paroleListener.rearmLatch();
+ setAppIdleEnabled(mController, false);
+ paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
+ assertTrue(paroleListener.mOnParole);
+ assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
+ }
+
private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
mInjector.mElapsedRealtime = elapsedTime;
controller.checkIdleStates(USER_ID);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 9c62700..e380d7a 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -30,18 +30,19 @@
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
@@ -340,14 +341,21 @@
}
void setAppIdleEnabled(boolean enabled) {
- mAppIdleEnabled = enabled;
+ synchronized (mAppIdleLock) {
+ if (mAppIdleEnabled != enabled) {
+ final boolean oldParoleState = isParoledOrCharging();
+ mAppIdleEnabled = enabled;
+ if (isParoledOrCharging() != oldParoleState) {
+ postParoleStateChanged();
+ }
+ }
+ }
}
public void onBootPhase(int phase) {
mInjector.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
Slog.d(TAG, "Setting app idle enabled state");
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Observe changes to the threshold
SettingsObserver settingsObserver = new SettingsObserver(mHandler);
settingsObserver.registerObserver();
@@ -1807,8 +1815,6 @@
mContext.getContentResolver(),
Global.APP_IDLE_CONSTANTS));
}
- // Check if app_idle_enabled has changed
- setAppIdleEnabled(mInjector.isAppIdleEnabled());
// Look at global settings for this.
// TODO: Maybe apply different thresholds for different users.
@@ -1880,6 +1886,10 @@
(KEY_STABLE_CHARGING_THRESHOLD,
COMPRESS_TIME ? ONE_MINUTE : DEFAULT_STABLE_CHARGING_THRESHOLD);
}
+
+ // Check if app_idle_enabled has changed. Do this after getting the rest of the settings
+ // in case we need to change something based on the new values.
+ setAppIdleEnabled(mInjector.isAppIdleEnabled());
}
long[] parseLongArray(String values, long[] defaults) {
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 7dc83c3..37caeb2 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",
],
@@ -58,6 +58,8 @@
"util.cc",
"layout_validation.cc",
],
+ // b/123880763, clang-tidy analyzer has segmentation fault with dex_builder.cc
+ tidy_checks: ["-clang-analyzer-*"],
host_supported: true,
}
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
index 7006075..5f7d3f9 100644
--- a/startop/view_compiler/TEST_MAPPING
+++ b/startop/view_compiler/TEST_MAPPING
@@ -4,6 +4,14 @@
"name": "dex-builder-test"
},
{
+ "name": "CtsViewTestCases",
+ "options": [
+ {
+ "include-filter": "android.view.cts.PrecompiledLayoutTest"
+ }
+ ]
+ },
+ {
"name": "view-compiler-tests",
"host": true
}
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index a78f7d5..4c1a0dc7 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -21,8 +21,6 @@
#include <fstream>
#include <memory>
-#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr)
-
namespace startop {
namespace dex {
@@ -32,6 +30,8 @@
using ::dex::kAccPublic;
using Op = Instruction::Op;
+using Opcode = ::art::Instruction::Code;
+
const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
@@ -42,6 +42,23 @@
// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
constexpr size_t kMaxEncodedStringLength{5};
+// Converts invoke-* to invoke-*/range
+constexpr Opcode InvokeToInvokeRange(Opcode opcode) {
+ switch (opcode) {
+ case ::art::Instruction::INVOKE_VIRTUAL:
+ return ::art::Instruction::INVOKE_VIRTUAL_RANGE;
+ case ::art::Instruction::INVOKE_DIRECT:
+ return ::art::Instruction::INVOKE_DIRECT_RANGE;
+ case ::art::Instruction::INVOKE_STATIC:
+ return ::art::Instruction::INVOKE_STATIC_RANGE;
+ case ::art::Instruction::INVOKE_INTERFACE:
+ return ::art::Instruction::INVOKE_INTERFACE_RANGE;
+ default:
+ LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
+ UNREACHABLE();
+ }
+}
+
} // namespace
std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
@@ -55,6 +72,9 @@
case Instruction::Op::kMove:
out << "kMove";
return out;
+ case Instruction::Op::kMoveObject:
+ out << "kMoveObject";
+ return out;
case Instruction::Op::kInvokeVirtual:
out << "kInvokeVirtual";
return out;
@@ -233,6 +253,11 @@
return shorty;
}
+const TypeDescriptor& Prototype::ArgType(size_t index) const {
+ CHECK_LT(index, param_types_.size());
+ return param_types_[index];
+}
+
ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
: parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
@@ -257,10 +282,10 @@
method->access_flags = kAccPublic | ::dex::kAccStatic;
auto* code = dex_->Alloc<ir::Code>();
- DCHECK_NOT_NULL(decl_->prototype);
+ CHECK(decl_->prototype != nullptr);
size_t const num_args =
decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
- code->registers = num_registers_ + num_args;
+ code->registers = num_registers_ + num_args + kMaxScratchRegisters;
code->ins_count = num_args;
EncodeInstructions();
code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
@@ -292,7 +317,7 @@
}
void MethodBuilder::BuildConst4(Value target, int value) {
- DCHECK_LT(value, 16);
+ CHECK_LT(value, 16);
AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
}
@@ -315,6 +340,7 @@
case Instruction::Op::kReturnObject:
return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
case Instruction::Op::kMove:
+ case Instruction::Op::kMoveObject:
return EncodeMove(instruction);
case Instruction::Op::kInvokeVirtual:
return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
@@ -338,33 +364,43 @@
}
void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
- DCHECK(!instruction.dest().has_value());
+ CHECK(!instruction.dest().has_value());
if (instruction.args().size() == 0) {
Encode10x(art::Instruction::RETURN_VOID);
} else {
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(1, instruction.args().size());
size_t source = RegisterValue(instruction.args()[0]);
Encode11x(opcode, source);
}
}
void MethodBuilder::EncodeMove(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kMove, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK(Instruction::Op::kMove == instruction.opcode() ||
+ Instruction::Op::kMoveObject == instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& source = instruction.args()[0];
if (source.is_immediate()) {
// TODO: support more registers
- DCHECK_LT(RegisterValue(*instruction.dest()), 16);
+ CHECK_LT(RegisterValue(*instruction.dest()), 16);
Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
} else if (source.is_string()) {
constexpr size_t kMaxRegisters = 256;
- DCHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
- DCHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
+ CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
+ CHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
+ } else if (source.is_variable()) {
+ // For the moment, we only use this when we need to reshuffle registers for
+ // an invoke instruction, meaning we are too big for the 4-bit version.
+ // We'll err on the side of caution and always generate the 16-bit form of
+ // the instruction.
+ Opcode opcode = instruction.opcode() == Instruction::Op::kMove
+ ? ::art::Instruction::MOVE_16
+ : ::art::Instruction::MOVE_OBJECT_16;
+ Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
} else {
UNIMPLEMENTED(FATAL);
}
@@ -373,22 +409,61 @@
void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
constexpr size_t kMaxArgs = 5;
+ // Currently, we only support up to 5 arguments.
CHECK_LE(instruction.args().size(), kMaxArgs);
uint8_t arguments[kMaxArgs]{};
+ bool has_long_args = false;
for (size_t i = 0; i < instruction.args().size(); ++i) {
CHECK(instruction.args()[i].is_variable());
arguments[i] = RegisterValue(instruction.args()[i]);
+ if (!IsShortRegister(arguments[i])) {
+ has_long_args = true;
+ }
}
- Encode35c(opcode,
- instruction.args().size(),
- instruction.method_id(),
- arguments[0],
- arguments[1],
- arguments[2],
- arguments[3],
- arguments[4]);
+ if (has_long_args) {
+ // Some of the registers don't fit in the four bit short form of the invoke
+ // instruction, so we need to do an invoke/range. To do this, we need to
+ // first move all the arguments into contiguous temporary registers.
+ std::array<Value, kMaxArgs> scratch{GetScratchRegisters<kMaxArgs>()};
+
+ const auto& prototype = dex_->GetPrototypeByMethodId(instruction.method_id());
+ CHECK(prototype.has_value());
+
+ for (size_t i = 0; i < instruction.args().size(); ++i) {
+ Instruction::Op move_op;
+ if (opcode == ::art::Instruction::INVOKE_VIRTUAL ||
+ opcode == ::art::Instruction::INVOKE_DIRECT) {
+ // In this case, there is an implicit `this` argument, which is always an object.
+ if (i == 0) {
+ move_op = Instruction::Op::kMoveObject;
+ } else {
+ move_op = prototype->ArgType(i - 1).is_object() ? Instruction::Op::kMoveObject
+ : Instruction::Op::kMove;
+ }
+ } else {
+ move_op = prototype->ArgType(i).is_object() ? Instruction::Op::kMoveObject
+ : Instruction::Op::kMove;
+ }
+
+ EncodeMove(Instruction::OpWithArgs(move_op, scratch[i], instruction.args()[i]));
+ }
+
+ Encode3rc(InvokeToInvokeRange(opcode),
+ instruction.args().size(),
+ instruction.method_id(),
+ RegisterValue(scratch[0]));
+ } else {
+ Encode35c(opcode,
+ instruction.args().size(),
+ instruction.method_id(),
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3],
+ arguments[4]);
+ }
// If there is a return value, add a move-result instruction
if (instruction.dest().has_value()) {
@@ -416,26 +491,26 @@
}
void MethodBuilder::EncodeNew(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kNew, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_variable());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(Instruction::Op::kNew, instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& type = instruction.args()[0];
- DCHECK_LT(RegisterValue(*instruction.dest()), 256);
- DCHECK(type.is_type());
+ CHECK_LT(RegisterValue(*instruction.dest()), 256);
+ CHECK(type.is_type());
Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
}
void MethodBuilder::EncodeCast(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_variable());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& type = instruction.args()[0];
- DCHECK_LT(RegisterValue(*instruction.dest()), 256);
- DCHECK(type.is_type());
+ CHECK_LT(RegisterValue(*instruction.dest()), 256);
+ CHECK(type.is_type());
Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
}
@@ -443,9 +518,9 @@
if (value.is_register()) {
return value.value();
} else if (value.is_parameter()) {
- return value.value() + num_registers_;
+ return value.value() + num_registers_ + kMaxScratchRegisters;
}
- DCHECK(false && "Must be either a parameter or a register");
+ CHECK(false && "Must be either a parameter or a register");
return 0;
}
@@ -498,7 +573,7 @@
// update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
auto new_index = dex_file_->methods_indexes.AllocateIndex();
auto& ir_node = dex_file_->methods_map[new_index];
- SLICER_CHECK(ir_node == nullptr);
+ CHECK(ir_node == nullptr);
ir_node = decl;
decl->orig_index = decl->index = new_index;
@@ -508,6 +583,15 @@
return entry;
}
+std::optional<const Prototype> DexBuilder::GetPrototypeByMethodId(size_t method_id) const {
+ for (const auto& entry : method_id_map_) {
+ if (entry.second.id == method_id) {
+ return entry.first.prototype;
+ }
+ }
+ return {};
+}
+
ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
ir::Proto*& ir_proto = proto_map_[prototype];
if (ir_proto == nullptr) {
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 757d863..541d800 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -16,6 +16,7 @@
#ifndef DEX_BUILDER_H_
#define DEX_BUILDER_H_
+#include <array>
#include <forward_list>
#include <map>
#include <optional>
@@ -70,6 +71,8 @@
// Return the shorty descriptor, such as I or L
std::string short_descriptor() const { return descriptor().substr(0, 1); }
+ bool is_object() const { return short_descriptor() == "L"; }
+
bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; }
private:
@@ -92,6 +95,8 @@
// Get the shorty descriptor, such as VII for (Int, Int) -> Void
std::string Shorty() const;
+ const TypeDescriptor& ArgType(size_t index) const;
+
bool operator<(const Prototype& rhs) const {
return std::make_tuple(return_type_, param_types_) <
std::make_tuple(rhs.return_type_, rhs.param_types_);
@@ -124,11 +129,13 @@
size_t value() const { return value_; }
- private:
- enum class Kind { kLocalRegister, kParameter, kImmediate, kString, kLabel, kType };
+ constexpr Value() : value_{0}, kind_{Kind::kInvalid} {}
- const size_t value_;
- const Kind kind_;
+ private:
+ enum class Kind { kInvalid, kLocalRegister, kParameter, kImmediate, kString, kLabel, kType };
+
+ size_t value_;
+ Kind kind_;
constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
};
@@ -151,6 +158,7 @@
kInvokeStatic,
kInvokeVirtual,
kMove,
+ kMoveObject,
kNew,
kReturn,
kReturnObject,
@@ -172,7 +180,7 @@
// A cast instruction. Basically, `(type)val`
static inline Instruction Cast(Value val, Value type) {
- DCHECK(type.is_type());
+ CHECK(type.is_type());
return OpWithArgs(Op::kCheckCast, val, type);
}
@@ -343,21 +351,48 @@
buffer_.push_back(b);
}
+ inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
+ buffer_.push_back(opcode);
+ buffer_.push_back(a);
+ buffer_.push_back(b);
+ }
+
inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
uint8_t e, uint8_t f, uint8_t g) {
// a|g|op|bbbb|f|e|d|c
CHECK_LE(a, 5);
- CHECK_LT(c, 16);
- CHECK_LT(d, 16);
- CHECK_LT(e, 16);
- CHECK_LT(f, 16);
- CHECK_LT(g, 16);
+ CHECK(IsShortRegister(c));
+ CHECK(IsShortRegister(d));
+ CHECK(IsShortRegister(e));
+ CHECK(IsShortRegister(f));
+ CHECK(IsShortRegister(g));
buffer_.push_back((a << 12) | (g << 8) | opcode);
buffer_.push_back(b);
buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c);
}
+ inline void Encode3rc(art::Instruction::Code opcode, size_t a, uint16_t b, uint16_t c) {
+ CHECK_LE(a, 255);
+ buffer_.push_back((a << 8) | opcode);
+ buffer_.push_back(b);
+ buffer_.push_back(c);
+ }
+
+ static constexpr bool IsShortRegister(size_t register_value) { return register_value < 16; }
+
+ // Returns an array of num_regs scratch registers. These are guaranteed to be
+ // contiguous, so they are suitable for the invoke-*/range instructions.
+ template <int num_regs>
+ std::array<Value, num_regs> GetScratchRegisters() const {
+ static_assert(num_regs <= kMaxScratchRegisters);
+ std::array<Value, num_regs> regs;
+ for (size_t i = 0; i < num_regs; ++i) {
+ regs[i] = std::move(Value::Local(num_registers_ + i));
+ }
+ return regs;
+ }
+
// Converts a register or parameter to its DEX register number.
size_t RegisterValue(const Value& value) const;
@@ -379,6 +414,10 @@
// A buffer to hold instructions that have been encoded.
std::vector<::dex::u2> buffer_;
+ // We create some scratch registers for when we have to shuffle registers
+ // around to make legal DEX code.
+ static constexpr size_t kMaxScratchRegisters = 5;
+
// How many registers we've allocated
size_t num_registers_{0};
@@ -447,6 +486,8 @@
const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
Prototype prototype);
+ std::optional<const Prototype> GetPrototypeByMethodId(size_t method_id) const;
+
private:
// Looks up the ir::Proto* corresponding to this given prototype, or creates one if it does not
// exist.
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
index 61c86b4..90c256f 100644
--- a/startop/view_compiler/dex_builder_test.cc
+++ b/startop/view_compiler/dex_builder_test.cc
@@ -140,3 +140,41 @@
EXPECT_TRUE(EncodeAndVerify(&dex_file));
}
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo(String s) { return s.length(); }
+// }
+TEST(DexBuilderTest, VerifyDexCallManyRegisters) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ MethodBuilder method{cbuilder.CreateMethod(
+ "foo", Prototype{TypeDescriptor::Int()})};
+
+ Value result = method.MakeRegister();
+
+ // Make a bunch of registers
+ for (size_t i = 0; i < 25; ++i) {
+ method.MakeRegister();
+ }
+
+ // Now load a string literal into a register
+ Value string_val = method.MakeRegister();
+ method.BuildConstString(string_val, "foo");
+
+ MethodDeclData string_length =
+ dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
+ "length",
+ Prototype{TypeDescriptor::Int()});
+
+ method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val));
+ method.BuildReturn(result);
+
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
index d4f38ed..ac60e96 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -15,7 +15,7 @@
//
genrule {
- name: "generate_compiled_layout",
+ name: "generate_compiled_layout1",
tools: [":viewcompiler"],
cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test",
srcs: ["res/layout/layout1.xml"],
@@ -24,6 +24,16 @@
],
}
+genrule {
+ name: "generate_compiled_layout2",
+ tools: [":viewcompiler"],
+ cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test",
+ srcs: ["res/layout/layout2.xml"],
+ out: [
+ "layout2.dex",
+ ],
+}
+
android_test {
name: "dex-builder-test",
srcs: [
@@ -31,7 +41,7 @@
"src/android/startop/test/LayoutCompilerTest.java",
],
sdk_version: "current",
- data: [":generate_dex_testcases", ":generate_compiled_layout"],
+ data: [":generate_dex_testcases", ":generate_compiled_layout1", ":generate_compiled_layout2"],
static_libs: [
"android-support-test",
"guava",
diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml
index 68d8fdc..92e2a71 100644
--- a/startop/view_compiler/dex_builder_test/AndroidTest.xml
+++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml
@@ -26,6 +26,7 @@
<option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" />
<option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" />
<option name="push" value="layout1.dex->/data/local/tmp/dex-builder-test/layout1.dex" />
+ <option name="push" value="layout2.dex->/data/local/tmp/dex-builder-test/layout2.dex" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/startop/view_compiler/dex_builder_test/res/layout/layout2.xml b/startop/view_compiler/dex_builder_test/res/layout/layout2.xml
new file mode 100644
index 0000000..b092e1c
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/res/layout/layout2.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+ </TableRow>
+
+ </TableRow>
+ </TableRow>
+ </TableRow>
+</LinearLayout>
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
index ce3ce83..a3b1b6c 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
@@ -36,11 +36,20 @@
}
@Test
- public void loadAndInflaterLayout1() throws Exception {
+ public void loadAndInflateLayout1() throws Exception {
ClassLoader dex_file = loadDexFile("layout1.dex");
Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView");
Method layout1 = compiled_view.getMethod("layout1", Context.class, int.class);
Context context = InstrumentationRegistry.getTargetContext();
layout1.invoke(null, context, R.layout.layout1);
}
+
+ @Test
+ public void loadAndInflateLayout2() throws Exception {
+ ClassLoader dex_file = loadDexFile("layout2.dex");
+ Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView");
+ Method layout1 = compiled_view.getMethod("layout2", Context.class, int.class);
+ Context context = InstrumentationRegistry.getTargetContext();
+ layout1.invoke(null, context, R.layout.layout1);
+ }
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2820836..dcaa499 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -239,6 +239,30 @@
"android.telecom.event.HANDOVER_FAILED";
public static class Details {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "DIRECTION_" },
+ value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING})
+ public @interface CallDirection {}
+
+ /**
+ * Indicates that the call is neither and incoming nor an outgoing call. This can be the
+ * case for calls reported directly by a {@link ConnectionService} in special cases such as
+ * call handovers.
+ */
+ public static final int DIRECTION_UNKNOWN = -1;
+
+ /**
+ * Indicates that the call is an incoming call.
+ */
+ public static final int DIRECTION_INCOMING = 0;
+
+ /**
+ * Indicates that the call is an outgoing call.
+ */
+ public static final int DIRECTION_OUTGOING = 1;
+
/** Call can currently be put on hold or unheld. */
public static final int CAPABILITY_HOLD = 0x00000001;
@@ -519,6 +543,7 @@
private final Bundle mIntentExtras;
private final long mCreationTimeMillis;
private final CallIdentification mCallIdentification;
+ private final @CallDirection int mCallDirection;
/**
* Whether the supplied capabilities supports the specified capability.
@@ -838,6 +863,14 @@
return mCallIdentification;
}
+ /**
+ * Indicates whether the call is an incoming or outgoing call.
+ * @return The call's direction.
+ */
+ public @CallDirection int getCallDirection() {
+ return mCallDirection;
+ }
+
@Override
public boolean equals(Object o) {
if (o instanceof Details) {
@@ -859,7 +892,8 @@
areBundlesEqual(mExtras, d.mExtras) &&
areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
- Objects.equals(mCallIdentification, d.mCallIdentification);
+ Objects.equals(mCallIdentification, d.mCallIdentification) &&
+ Objects.equals(mCallDirection, d.mCallDirection);
}
return false;
}
@@ -881,7 +915,8 @@
mExtras,
mIntentExtras,
mCreationTimeMillis,
- mCallIdentification);
+ mCallIdentification,
+ mCallDirection);
}
/** {@hide} */
@@ -902,7 +937,8 @@
Bundle extras,
Bundle intentExtras,
long creationTimeMillis,
- CallIdentification callIdentification) {
+ CallIdentification callIdentification,
+ int callDirection) {
mTelecomCallId = telecomCallId;
mHandle = handle;
mHandlePresentation = handlePresentation;
@@ -920,6 +956,7 @@
mIntentExtras = intentExtras;
mCreationTimeMillis = creationTimeMillis;
mCallIdentification = callIdentification;
+ mCallDirection = callDirection;
}
/** {@hide} */
@@ -941,7 +978,8 @@
parcelableCall.getExtras(),
parcelableCall.getIntentExtras(),
parcelableCall.getCreationTimeMillis(),
- parcelableCall.getCallIdentification());
+ parcelableCall.getCallIdentification(),
+ parcelableCall.getCallDirection());
}
@Override
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index 97af06c..87834fd 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -250,8 +250,8 @@
mDetails = details;
mPhoto = photo;
mNuisanceConfidence = nuisanceConfidence;
- mCallScreeningAppName = callScreeningPackageName;
- mCallScreeningPackageName = callScreeningAppName;
+ mCallScreeningAppName = callScreeningAppName;
+ mCallScreeningPackageName = callScreeningPackageName;
}
private String mName;
@@ -430,4 +430,22 @@
return Objects.hash(mName, mDescription, mDetails, mPhoto, mNuisanceConfidence,
mCallScreeningAppName, mCallScreeningPackageName);
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[CallId mName=");
+ sb.append(Log.pii(mName));
+ sb.append(", mDesc=");
+ sb.append(mDescription);
+ sb.append(", mDet=");
+ sb.append(mDetails);
+ sb.append(", conf=");
+ sb.append(mNuisanceConfidence);
+ sb.append(", appName=");
+ sb.append(mCallScreeningAppName);
+ sb.append(", pkgName=");
+ sb.append(mCallScreeningPackageName);
+ return sb.toString();
+ }
}
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index be96b3c..818ebd9 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -16,11 +16,13 @@
package android.telecom;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
+import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -31,10 +33,14 @@
import com.android.internal.telecom.ICallScreeningAdapter;
import com.android.internal.telecom.ICallScreeningService;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This service can be implemented by the default dialer (see
- * {@link TelecomManager#getDefaultDialerPackage()}) to allow or disallow incoming calls before
- * they are shown to a user.
+ * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
+ * incoming calls before they are shown to a user. This service can also provide
+ * {@link CallIdentification} information for calls.
* <p>
* Below is an example manifest registration for a {@code CallScreeningService}.
* <pre>
@@ -56,8 +62,158 @@
* information about a {@link Call.Details call} which will be shown to the user in the
* Dialer app.</li>
* </ol>
+ * <p>
+ * <h2>Becoming the {@link CallScreeningService}</h2>
+ * Telecom will bind to a single app chosen by the user which implements the
+ * {@link CallScreeningService} API when there are new incoming and outgoing calls.
+ * <p>
+ * The code snippet below illustrates how your app can request that it fills the call screening
+ * role.
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
+ * startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * @Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ * if (requestCode == REQUEST_ID) {
+ * if (resultCode == android.app.Activity.RESULT_OK) {
+ * // Your app is now the call screening app
+ * } else {
+ * // Your app is not the call screening app
+ * }
+ * }
+ * }
+ * </pre>
*/
public abstract class CallScreeningService extends Service {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = { "CALL_DURATION_" },
+ value = {CALL_DURATION_VERY_SHORT, CALL_DURATION_SHORT, CALL_DURATION_MEDIUM,
+ CALL_DURATION_LONG})
+ public @interface CallDuration {}
+
+ /**
+ * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+ * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+ * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
+ * {@link CallScreeningService} can use this as a signal for training nuisance detection
+ * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
+ * identifying call log information to the {@link CallScreeningService}.
+ * <p>
+ * Indicates the call was < 3 seconds in duration.
+ */
+ public static final int CALL_DURATION_VERY_SHORT = 1;
+
+ /**
+ * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+ * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+ * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
+ * {@link CallScreeningService} can use this as a signal for training nuisance detection
+ * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
+ * identifying call log information to the {@link CallScreeningService}.
+ * <p>
+ * Indicates the call was greater than 3 seconds, but less than 60 seconds in duration.
+ */
+ public static final int CALL_DURATION_SHORT = 2;
+
+ /**
+ * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+ * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+ * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
+ * {@link CallScreeningService} can use this as a signal for training nuisance detection
+ * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
+ * identifying call log information to the {@link CallScreeningService}.
+ * <p>
+ * Indicates the call was greater than 60 seconds, but less than 120 seconds in duration.
+ */
+ public static final int CALL_DURATION_MEDIUM = 3;
+
+ /**
+ * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
+ * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
+ * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
+ * {@link CallScreeningService} can use this as a signal for training nuisance detection
+ * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
+ * identifying call log information to the {@link CallScreeningService}.
+ * <p>
+ * Indicates the call was greater than 120 seconds.
+ */
+ public static final int CALL_DURATION_LONG = 4;
+
+ /**
+ * Telecom sends this intent to the {@link CallScreeningService} which the user has chosen to
+ * fill the call screening role when the user indicates through the default dialer whether a
+ * call is a nuisance call or not (see
+ * {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).
+ * <p>
+ * The following extra values are provided for the call:
+ * <ol>
+ * <li>{@link #EXTRA_CALL_HANDLE} - the handle of the call.</li>
+ * <li>{@link #EXTRA_IS_NUISANCE} - {@code true} if the user reported the call as a nuisance
+ * call, {@code false} otherwise.</li>
+ * <li>{@link #EXTRA_CALL_TYPE} - reports the type of call (incoming, rejected, missed,
+ * blocked).</li>
+ * <li>{@link #EXTRA_CALL_DURATION} - the duration of the call (see
+ * {@link #EXTRA_CALL_DURATION} for valid values).</li>
+ * </ol>
+ * <p>
+ * {@link CallScreeningService} implementations which want to track whether the user reports
+ * calls are nuisance calls should use declare a broadcast receiver in their manifest for this
+ * intent.
+ * <p>
+ * Note: Only {@link CallScreeningService} implementations which have provided
+ * {@link CallIdentification} information for calls at some point will receive this intent.
+ */
+ public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED =
+ "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
+
+ /**
+ * Extra used to provide the handle of the call for
+ * {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}. The call handle is reported as a
+ * {@link Uri}.
+ */
+ public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
+
+ /**
+ * Boolean extra used to indicate whether the user reported a call as a nuisance call.
+ * When {@code true}, the user reported that a call was a nuisance call, {@code false}
+ * otherwise. Sent with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}.
+ */
+ public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
+
+ /**
+ * Integer extra used with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report the type of
+ * call. Valid values are:
+ * <UL>
+ * <li>{@link android.provider.CallLog.Calls#MISSED_TYPE}</li>
+ * <li>{@link android.provider.CallLog.Calls#INCOMING_TYPE}</li>
+ * <li>{@link android.provider.CallLog.Calls#BLOCKED_TYPE}</li>
+ * <li>{@link android.provider.CallLog.Calls#REJECTED_TYPE}</li>
+ * </UL>
+ */
+ public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
+
+ /**
+ * Integer extra used to with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report how long
+ * the call lasted. Valid values are:
+ * <UL>
+ * <LI>{@link #CALL_DURATION_VERY_SHORT}</LI>
+ * <LI>{@link #CALL_DURATION_SHORT}</LI>
+ * <LI>{@link #CALL_DURATION_MEDIUM}</LI>
+ * <LI>{@link #CALL_DURATION_LONG}</LI>
+ * </UL>
+ */
+ public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
+
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -222,30 +378,46 @@
}
/**
- * Called when a new incoming call is added.
- * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
- * should be called to allow or disallow the call.
+ * Called when a new incoming or outgoing call is added which is not in the user's contact list.
+ * <p>
+ * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
+ * calling
+ * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
+ * Your app can tell if a call is an incoming call by checking to see if
+ * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
+ * <p>
+ * For incoming or outgoing calls, the {@link CallScreeningService} can call
+ * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
+ * {@link CallIdentification} for the call.
* <p>
* Note: The {@link Call.Details} instance provided to a call screening service will only have
* the following properties set. The rest of the {@link Call.Details} properties will be set to
* their default value or {@code null}.
* <ul>
- * <li>{@link Call.Details#getState()}</li>
+ * <li>{@link Call.Details#getCallDirection()}</li>
* <li>{@link Call.Details#getConnectTimeMillis()}</li>
* <li>{@link Call.Details#getCreationTimeMillis()}</li>
* <li>{@link Call.Details#getHandle()}</li>
* <li>{@link Call.Details#getHandlePresentation()}</li>
* </ul>
+ * <p>
+ * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
+ * is {@link PhoneAccount#SCHEME_TEL} are passed for call
+ * screening. Further, only calls which are not in the user's contacts are passed for
+ * screening. For outgoing calls, no post-dial digits are passed.
*
- * @param callDetails Information about a new incoming call, see {@link Call.Details}.
+ * @param callDetails Information about a new call, see {@link Call.Details}.
*/
public abstract void onScreenCall(@NonNull Call.Details callDetails);
/**
- * Responds to the given call, either allowing it or disallowing it.
+ * Responds to the given incoming call, either allowing it or disallowing it.
* <p>
* The {@link CallScreeningService} calls this method to inform the system whether the call
* should be silently blocked or not.
+ * <p>
+ * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
+ * {@link Call.Details#DIRECTION_INCOMING}.
*
* @param callDetails The call to allow.
* <p>
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 1aeeca7..cea2fbf 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -40,11 +40,30 @@
import java.util.List;
/**
- * This service is implemented by any app that wishes to provide the user-interface for managing
- * phone calls. Telecom binds to this service while there exists a live (active or incoming) call,
- * and uses it to notify the in-call app of any live and recently disconnected calls. An app must
- * first be set as the default phone app (See {@link TelecomManager#getDefaultDialerPackage()})
- * before the telecom service will bind to its {@code InCallService} implementation.
+ * This service is implemented by an app that wishes to provide functionality for managing
+ * phone calls.
+ * <p>
+ * There are three types of apps which Telecom can bind to when there exists a live (active or
+ * incoming) call:
+ * <ol>
+ * <li>Default Dialer/Phone app - the default dialer/phone app is one which provides the
+ * in-call user interface while the device is in a call. A device is bundled with a system
+ * provided default dialer/phone app. The user may choose a single app to take over this role
+ * from the system app.</li>
+ * <li>Default Car-mode Dialer/Phone app - the default car-mode dialer/phone app is one which
+ * provides the in-call user interface while the device is in a call and the device is in car
+ * mode. The user may choose a single app to fill this role.</li>
+ * <li>Call Companion app - a call companion app is one which provides no user interface itself,
+ * but exposes call information to another display surface, such as a wearable device. The
+ * user may choose multiple apps to fill this role.</li>
+ * </ol>
+ * <p>
+ * Apps which wish to fulfill one of the above roles use the {@code android.app.role.RoleManager}
+ * to request that they fill the desired role.
+ *
+ * <h2>Becoming the Default Phone App</h2>
+ * An app filling the role of the default phone app provides a user interface while the device is in
+ * a call, and the device is not in car mode.
* <p>
* Below is an example manifest registration for an {@code InCallService}. The meta-data
* {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} indicates that this particular
@@ -82,12 +101,34 @@
* }
* </pre>
* <p>
- * When a user installs your application and runs it for the first time, you should prompt the user
- * to see if they would like your application to be the new default phone app. See the
- * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on
- * how to do this.
+ * When a user installs your application and runs it for the first time, you should use the
+ * {@code android.app.role.RoleManager} to prompt the user to see if they would like your app to
+ * be the new default phone app.
+ * <p id="requestRole">
+ * The code below shows how your app can request to become the default phone/dialer app:
+ * <pre>
+ * {@code
+ * private static final int REQUEST_ID = 1;
+ *
+ * public void requestRole() {
+ * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
+ * Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
+ * startActivityForResult(intent, REQUEST_ID);
+ * }
+ *
+ * @Override
+ * public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ * if (requestCode == REQUEST_ID) {
+ * if (resultCode == android.app.Activity.RESULT_OK) {
+ * // Your app is now the default dialer app
+ * } else {
+ * // Your app is not the default dialer app
+ * }
+ * }
+ * }
+ * </pre>
* <p id="incomingCallNotification">
- * <h2>Showing the Incoming Call Notification</h2>
+ * <h3>Showing the Incoming Call Notification</h3>
* When your app receives a new incoming call via {@link InCallService#onCallAdded(Call)}, it is
* responsible for displaying an incoming call UI for the incoming call. It should do this using
* {@link android.app.NotificationManager} APIs to post a new incoming call notification.
@@ -121,7 +162,7 @@
* heads-up notification if the user is actively using the phone. When the user is not using the
* phone, your full-screen incoming call UI is used instead.
* For example:
- * <pre><code>
+ * <pre><code>{@code
* // Create an intent which triggers your fullscreen incoming call user interface.
* Intent intent = new Intent(Intent.ACTION_MAIN, null);
* intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -151,7 +192,49 @@
* NotificationManager notificationManager = mContext.getSystemService(
* NotificationManager.class);
* notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
- * </code></pre>
+ * }</pre>
+ * <p>
+ * <h2>Becoming the Default Car-mode Phone App</h2>
+ * An app filling the role of the default car-mode dialer/phone app provides a user interface while
+ * the device is in a call, and in car mode. See
+ * {@link android.app.UiModeManager#ACTION_ENTER_CAR_MODE} for more information about car mode.
+ * When the device is in car mode, Telecom binds to the default car-mode dialer/phone app instead
+ * of the usual dialer/phone app.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation. Your manifest entry should ensure
+ * the following conditions are met:
+ * <ul>
+ * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ * <li>Set the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI} metadata to
+ * {@code true}<li>
+ * <li>Your app must request the permission
+ * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to
+ * become the default (see <a href="#requestRole">above</a> for how to request your app fills this
+ * role).
+ *
+ * <h2>Becoming a Call Companion App</h2>
+ * An app which fills the companion app role does not directly provide a user interface while the
+ * device is in a call. Instead, it is typically used to relay information about calls to another
+ * display surface, such as a wearable device.
+ * <p>
+ * Similar to the requirements for becoming the default dialer/phone app, your app must declare a
+ * manifest entry for its {@link InCallService} implementation. Your manifest entry should
+ * ensure the following conditions are met:
+ * <ul>
+ * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_UI} metadata.</li>
+ * <li>Do NOT declare the {@link TelecomManager#METADATA_IN_CALL_SERVICE_CAR_MODE_UI}
+ * metadata.</li>
+ * <li>Your app must request the permission
+ * {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
+ * </ul>
+ * <p>
+ * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to
+ * become a call companion app (see <a href="#requestRole">above</a> for how to request your app
+ * fills this role).
*/
public abstract class InCallService extends Service {
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 911786e..f7dec83 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -24,6 +24,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
+import android.telecom.Call.Details.CallDirection;
import java.util.ArrayList;
import java.util.Collections;
@@ -64,6 +65,7 @@
private final Bundle mExtras;
private final long mCreationTimeMillis;
private final CallIdentification mCallIdentification;
+ private final int mCallDirection;
public ParcelableCall(
String id,
@@ -92,7 +94,8 @@
Bundle intentExtras,
Bundle extras,
long creationTimeMillis,
- CallIdentification callIdentification) {
+ CallIdentification callIdentification,
+ int callDirection) {
mId = id;
mState = state;
mDisconnectCause = disconnectCause;
@@ -120,6 +123,7 @@
mExtras = extras;
mCreationTimeMillis = creationTimeMillis;
mCallIdentification = callIdentification;
+ mCallDirection = callDirection;
}
/** The unique ID of the call. */
@@ -318,6 +322,13 @@
return mCallIdentification;
}
+ /**
+ * Indicates whether the call is an incoming or outgoing call.
+ */
+ public @CallDirection int getCallDirection() {
+ return mCallDirection;
+ }
+
/** Responsible for creating ParcelableCall objects for deserialized Parcels. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final Parcelable.Creator<ParcelableCall> CREATOR =
@@ -356,6 +367,7 @@
ParcelableRttCall rttCall = source.readParcelable(classLoader);
long creationTimeMillis = source.readLong();
CallIdentification callIdentification = source.readParcelable(classLoader);
+ int callDirection = source.readInt();
return new ParcelableCall(
id,
state,
@@ -383,7 +395,8 @@
intentExtras,
extras,
creationTimeMillis,
- callIdentification);
+ callIdentification,
+ callDirection);
}
@Override
@@ -429,6 +442,7 @@
destination.writeParcelable(mRttCall, 0);
destination.writeLong(mCreationTimeMillis);
destination.writeParcelable(mCallIdentification, 0);
+ destination.writeInt(mCallDirection);
}
@Override
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c3e80b4..268e70f 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1397,8 +1397,14 @@
*
* @return {@code true} if there is a call which will be rejected or terminated, {@code false}
* otherwise.
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead. Apps performing call screening should use the {@link CallScreeningService} API
+ * instead.
*/
+
+
@RequiresPermission(Manifest.permission.ANSWER_PHONE_CALLS)
+ @Deprecated
public boolean endCall() {
try {
if (isServiceConnected()) {
@@ -1419,11 +1425,15 @@
*
* Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
* {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
+ *
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead.
*/
//TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
// this method (clockwork & gearhead).
@RequiresPermission(anyOf =
{Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
+ @Deprecated
public void acceptRingingCall() {
try {
if (isServiceConnected()) {
@@ -1442,9 +1452,12 @@
* {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
*
* @param videoState The desired video state to answer the call with.
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead.
*/
@RequiresPermission(anyOf =
{Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
+ @Deprecated
public void acceptRingingCall(int videoState) {
try {
if (isServiceConnected()) {
@@ -1963,6 +1976,33 @@
}
/**
+ * Called by the default dialer to report to Telecom when the user has marked a previous
+ * incoming call as a nuisance call or not.
+ * <p>
+ * Where the user has chosen a {@link CallScreeningService} to fill the call screening role,
+ * Telecom will notify that {@link CallScreeningService} of the user's report.
+ * <p>
+ * Requires that the caller is the default dialer app.
+ *
+ * @param handle The phone number of an incoming call which the user is reporting as either a
+ * nuisance of non-nuisance call.
+ * @param isNuisanceCall {@code true} if the user is reporting the call as a nuisance call,
+ * {@code false} if the user is reporting the call as a non-nuisance call.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public void reportNuisanceCallStatus(@NonNull Uri handle, boolean isNuisanceCall) {
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ try {
+ service.reportNuisanceCallStatus(handle, isNuisanceCall,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
+ }
+ }
+ }
+
+ /**
* Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
* @param intent The {@link Intent#ACTION_CALL} intent to handle.
* @hide
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/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index e1d5c17..5030f90 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -285,6 +285,8 @@
*/
boolean isInEmergencyCall();
+ oneway void reportNuisanceCallStatus(in Uri address, boolean isNuisance, String callingPackage);
+
/**
* @see TelecomServiceImpl#handleCallIntent
*/
@@ -299,4 +301,5 @@
void addOrRemoveTestCallCompanionApp(String packageName, boolean isAdded);
void setTestAutoModeApp(String packageName);
+
}
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index 4da79b3..b407b2a 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -114,7 +114,7 @@
in.readStringList(mMccMncs);
}
- public AvailableNetworkInfo(int subId, int priority, ArrayList<String> mccMncs) {
+ public AvailableNetworkInfo(int subId, int priority, List<String> mccMncs) {
mSubId = subId;
mPriority = priority;
mMccMncs = new ArrayList<String>(mccMncs);
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 2b99ce1..0d4f09f 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -50,10 +50,9 @@
}
private CallAttributes(Parcel in) {
- mPreciseCallState = (PreciseCallState) in.readValue(mPreciseCallState.getClass()
- .getClassLoader());
- mNetworkType = in.readInt();
- mCallQuality = (CallQuality) in.readValue(mCallQuality.getClass().getClassLoader());
+ this.mPreciseCallState = in.readParcelable(PreciseCallState.class.getClassLoader());
+ this.mNetworkType = in.readInt();
+ this.mCallQuality = in.readParcelable(CallQuality.class.getClassLoader());
}
// getters
@@ -118,9 +117,9 @@
CallAttributes s = (CallAttributes) o;
- return (mPreciseCallState == s.mPreciseCallState
+ return (Objects.equals(mPreciseCallState, s.mPreciseCallState)
&& mNetworkType == s.mNetworkType
- && mCallQuality == s.mCallQuality);
+ && Objects.equals(mCallQuality, s.mCallQuality));
}
/**
@@ -134,9 +133,9 @@
* {@link Parcelable#writeToParcel}
*/
public void writeToParcel(Parcel dest, @Parcelable.WriteFlags int flags) {
- mPreciseCallState.writeToParcel(dest, flags);
+ dest.writeParcelable(mPreciseCallState, flags);
dest.writeInt(mNetworkType);
- mCallQuality.writeToParcel(dest, flags);
+ dest.writeParcelable(mCallQuality, flags);
}
public static final Parcelable.Creator<CallAttributes> CREATOR = new Parcelable.Creator() {
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/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 061cd4b..6f84ec5 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -77,6 +77,14 @@
}
/**
+ * @hide
+ * @param ss signal strength from modem.
+ */
+ public CellSignalStrengthNr(android.hardware.radio.V1_4.NrSignalStrength ss) {
+ this(ss.csiRsrp, ss.csiRsrq, ss.csiSinr, ss.ssRsrp, ss.ssRsrq, ss.ssSinr);
+ }
+
+ /**
* Reference: 3GPP TS 38.215.
* Range: -140 dBm to -44 dBm.
* @return SS reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported
diff --git a/telephony/java/android/telephony/DebugEventReporter.java b/telephony/java/android/telephony/DebugEventReporter.java
new file mode 100644
index 0000000..14b7dd6
--- /dev/null
+++ b/telephony/java/android/telephony/DebugEventReporter.java
@@ -0,0 +1,174 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.ParcelUuid;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A Simple Surface for Telephony to notify a loosely-coupled debugger of particular issues.
+ *
+ * DebugEventReporter allows an optional external logging component to receive events detected by
+ * the framework and take action. This log surface is designed to provide maximium flexibility
+ * to the receiver of these events. Envisioned use cases of this include notifying a vendor
+ * component of: an event that necessitates (timely) log collection on non-AOSP components;
+ * notifying a vendor component of a rare event that should prompt further action such as a
+ * bug report or user intervention for debug purposes.
+ *
+ * <p>This surface is not intended to enable a diagnostic monitor, nor is it intended to support
+ * streaming logs.
+ *
+ * @hide
+ */
+public final class DebugEventReporter {
+ private static final String TAG = "DebugEventReporter";
+
+ private static Context sContext = null;
+
+ private static Map<UUID, Integer> sEvents = new ConcurrentHashMap<>();
+
+ /*
+ * Because this is only supporting system packages, once we find a package, it will be the
+ * same package until the next system upgrade. Thus, to save time in processing debug events
+ * we can cache this info and skip the resolution process after it's done the first time.
+ */
+ private static String sDebugPackageName = null;
+
+ private DebugEventReporter() {};
+
+ /**
+ * If enabled, build and send an intent to a Debug Service for logging.
+ *
+ * This method sends the {@link TelephonyManager#DEBUG_EVENT DEBUG_EVENT} broadcast, which is
+ * system protected. Invoking this method unless you are the system will result in an error.
+ *
+ * @param eventId a fixed event ID that will be sent for each instance of the same event. This
+ * ID should be generated randomly.
+ * @param description an optional description, that if included will be used as the subject for
+ * identification and discussion of this event. This description should ideally be
+ * static and must not contain any sensitive information (especially PII).
+ */
+ public static void sendEvent(@NonNull UUID eventId, String description) {
+ if (sContext == null) {
+ Rlog.w(TAG, "DebugEventReporter not yet initialized, dropping event=" + eventId);
+ return;
+ }
+
+ // If this event has already occurred, skip sending intents for it; regardless log its
+ // invocation here.
+ Integer count = sEvents.containsKey(eventId) ? sEvents.get(eventId) + 1 : 1;
+ sEvents.put(eventId, count);
+ if (count > 1) return;
+
+ // Even if we are initialized, that doesn't mean that a package name has been found.
+ // This is normal in many cases, such as when no debug package is installed on the system,
+ // so drop these events silently.
+ if (sDebugPackageName == null) return;
+
+ Intent dbgIntent = new Intent(TelephonyManager.ACTION_DEBUG_EVENT);
+ dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_ID, new ParcelUuid(eventId));
+ if (description != null) {
+ dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_DESCRIPTION, description);
+ }
+ dbgIntent.setPackage(sDebugPackageName);
+ sContext.sendBroadcast(dbgIntent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ }
+
+ /**
+ * Initialize the DebugEventReporter with the current context.
+ *
+ * This method must be invoked before any calls to sendEvent() will succeed. This method should
+ * only be invoked at most once.
+ *
+ * @param context a Context object used to initialize this singleton DebugEventReporter in
+ * the current process.
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public static void initialize(@NonNull Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("DebugEventReporter needs a non-null context.");
+ }
+
+ // Ensure that this context has sufficient permissions to send debug events.
+ context.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
+ "This app does not have privileges to send debug events");
+
+ sContext = context;
+
+ // Check to see if there is a valid debug package; if there are multiple, that's a config
+ // error, so just take the first one.
+ PackageManager pm = sContext.getPackageManager();
+ if (pm == null) return;
+ List<ResolveInfo> packages = pm.queryBroadcastReceivers(
+ new Intent(TelephonyManager.ACTION_DEBUG_EVENT),
+ PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ if (packages == null || packages.isEmpty()) return;
+ if (packages.size() > 1) {
+ Rlog.e(TAG, "Multiple DebugEvent Receivers installed.");
+ }
+
+ for (ResolveInfo r : packages) {
+ if (r.activityInfo == null
+ || pm.checkPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ r.activityInfo.packageName)
+ != PackageManager.PERMISSION_GRANTED) {
+ Rlog.w(TAG,
+ "Found package without proper permissions or no activity"
+ + r.activityInfo.packageName);
+ continue;
+ }
+ Rlog.d(TAG, "Found a valid package " + r.activityInfo.packageName);
+ sDebugPackageName = r.activityInfo.packageName;
+ break;
+ }
+ // Initialization may only be performed once.
+ }
+
+ /** Dump the contents of the DebugEventReporter */
+ public static void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ if (sContext == null) return;
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ sContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
+ pw.println("Initialized=" + (sContext != null ? "Yes" : "No"));
+ pw.println("Debug Package=" + sDebugPackageName);
+ pw.println("Event Counts:");
+ pw.increaseIndent();
+ for (UUID event : sEvents.keySet()) {
+ pw.println(event + ": " + sEvents.get(event));
+ }
+ pw.decreaseIndent();
+ pw.flush();
+ }
+}
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 4bca404..6c45cc4 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
@@ -112,13 +113,13 @@
mSlotId, 0, null).sendToTarget();
}
- private void registerForStateChanged(INetworkServiceCallback callback) {
+ private void registerForStateChanged(@NonNull INetworkServiceCallback callback) {
synchronized (mNetworkRegistrationStateChangedCallbacks) {
mNetworkRegistrationStateChangedCallbacks.add(callback);
}
}
- private void unregisterForStateChanged(INetworkServiceCallback callback) {
+ private void unregisterForStateChanged(@NonNull INetworkServiceCallback callback) {
synchronized (mNetworkRegistrationStateChangedCallbacks) {
mNetworkRegistrationStateChangedCallbacks.remove(callback);
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9fee593..fea1b7b 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -28,6 +28,7 @@
import android.os.HandlerExecutor;
import android.os.Looper;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IPhoneStateListener;
@@ -347,6 +348,20 @@
@SystemApi
public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000;
+ /**
+ * Listen for IMS call disconnect causes which contains
+ * {@link android.telephony.ims.ImsReasonInfo}
+ *
+ * {@more}
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE}
+ *
+ * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
+ * @hide
+ */
+ @SystemApi
+ public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 0x08000000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -578,6 +593,17 @@
}
/**
+ * Callback invoked when Ims call disconnect cause changes.
+ * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
+ // default implementation empty
+ }
+
+ /**
* Callback invoked when data connection state changes with precise information.
* @param dataConnectionState {@link PreciseDataConnectionState}
*
@@ -701,7 +727,7 @@
* @hide
*/
@SystemApi
- public void onCallAttributesChanged(CallAttributes callAttributes) {
+ public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
// default implementation empty
}
@@ -981,6 +1007,16 @@
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> psl.onPreferredDataSubIdChanged(subId)));
}
+
+ public void onImsCallDisconnectCauseChanged(ImsReasonInfo disconnectCause) {
+ PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+ if (psl == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> psl.onImsCallDisconnectCauseChanged(disconnectCause)));
+
+ }
}
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 59f3e1f..19e1931 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -287,11 +287,11 @@
return false;
}
PreciseCallState other = (PreciseCallState) obj;
- return (mRingingCallState != other.mRingingCallState &&
- mForegroundCallState != other.mForegroundCallState &&
- mBackgroundCallState != other.mBackgroundCallState &&
- mDisconnectCause != other.mDisconnectCause &&
- mPreciseDisconnectCause != other.mPreciseDisconnectCause);
+ return (mRingingCallState == other.mRingingCallState
+ && mForegroundCallState == other.mForegroundCallState
+ && mBackgroundCallState == other.mBackgroundCallState
+ && mDisconnectCause == other.mDisconnectCause
+ && mPreciseDisconnectCause == other.mPreciseDisconnectCause);
}
@Override
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index f63b753..0d94c4d 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -57,6 +57,9 @@
public static final int RAF_LTE = TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
public static final int RAF_LTE_CA = TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
+ // 5G
+ public static final int RAF_NR = TelephonyManager.NETWORK_TYPE_BITMASK_NR;
+
// Grouping of RAFs
// 2G
private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE;
@@ -68,6 +71,9 @@
// 4G
private static final int LTE = RAF_LTE | RAF_LTE_CA;
+ // 5G
+ private static final int NR = RAF_NR;
+
/* Phone ID of phone */
private int mPhoneId;
@@ -160,84 +166,78 @@
@UnsupportedAppUsage
public static int getRafFromNetworkType(int type) {
- int raf;
-
switch (type) {
case RILConstants.NETWORK_MODE_WCDMA_PREF:
- raf = GSM | WCDMA;
- break;
+ return GSM | WCDMA;
case RILConstants.NETWORK_MODE_GSM_ONLY:
- raf = GSM;
- break;
+ return GSM;
case RILConstants.NETWORK_MODE_WCDMA_ONLY:
- raf = WCDMA;
- break;
+ return WCDMA;
case RILConstants.NETWORK_MODE_GSM_UMTS:
- raf = GSM | WCDMA;
- break;
+ return GSM | WCDMA;
case RILConstants.NETWORK_MODE_CDMA:
- raf = CDMA | EVDO;
- break;
+ return CDMA | EVDO;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
- raf = LTE | CDMA | EVDO;
- break;
+ return LTE | CDMA | EVDO;
case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
- raf = LTE | GSM | WCDMA;
- break;
+ return LTE | GSM | WCDMA;
case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
- raf = LTE | CDMA | EVDO | GSM | WCDMA;
- break;
+ return LTE | CDMA | EVDO | GSM | WCDMA;
case RILConstants.NETWORK_MODE_LTE_ONLY:
- raf = LTE;
- break;
+ return LTE;
case RILConstants.NETWORK_MODE_LTE_WCDMA:
- raf = LTE | WCDMA;
- break;
+ return LTE | WCDMA;
case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
- raf = CDMA;
- break;
+ return CDMA;
case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
- raf = EVDO;
- break;
+ return EVDO;
case RILConstants.NETWORK_MODE_GLOBAL:
- raf = GSM | WCDMA | CDMA | EVDO;
- break;
+ return GSM | WCDMA | CDMA | EVDO;
case RILConstants.NETWORK_MODE_TDSCDMA_ONLY:
- raf = RAF_TD_SCDMA;
- break;
+ return RAF_TD_SCDMA;
case RILConstants.NETWORK_MODE_TDSCDMA_WCDMA:
- raf = RAF_TD_SCDMA | WCDMA;
- break;
+ return RAF_TD_SCDMA | WCDMA;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA:
- raf = LTE | RAF_TD_SCDMA;
- break;
+ return LTE | RAF_TD_SCDMA;
case RILConstants.NETWORK_MODE_TDSCDMA_GSM:
- raf = RAF_TD_SCDMA | GSM;
- break;
+ return RAF_TD_SCDMA | GSM;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM:
- raf = LTE | RAF_TD_SCDMA | GSM;
- break;
+ return LTE | RAF_TD_SCDMA | GSM;
case RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
- raf = RAF_TD_SCDMA | GSM | WCDMA;
- break;
+ return RAF_TD_SCDMA | GSM | WCDMA;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA:
- raf = LTE | RAF_TD_SCDMA | WCDMA;
- break;
+ return LTE | RAF_TD_SCDMA | WCDMA;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA:
- raf = LTE | RAF_TD_SCDMA | GSM | WCDMA;
- break;
+ return LTE | RAF_TD_SCDMA | GSM | WCDMA;
case RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
- raf = RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
- break;
+ return RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
- raf = LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
- break;
+ return LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_ONLY):
+ return NR;
+ case (RILConstants.NETWORK_MODE_NR_LTE):
+ return NR | LTE;
+ case (RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO):
+ return NR | LTE | CDMA | EVDO;
+ case (RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA):
+ return NR | LTE | GSM | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA):
+ return NR | LTE | CDMA | EVDO | GSM | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_WCDMA):
+ return NR | LTE | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA):
+ return NR | LTE | RAF_TD_SCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM):
+ return NR | LTE | RAF_TD_SCDMA | GSM;
+ case (RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA):
+ return NR | LTE | RAF_TD_SCDMA | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA):
+ return NR | LTE | RAF_TD_SCDMA | GSM | WCDMA;
+ case (RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA):
+ return NR | LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
default:
- raf = RAF_UNKNOWN;
- break;
+ return RAF_UNKNOWN;
}
-
- return raf;
}
/**
@@ -250,6 +250,7 @@
raf = ((CDMA & raf) > 0) ? (CDMA | raf) : raf;
raf = ((EVDO & raf) > 0) ? (EVDO | raf) : raf;
raf = ((LTE & raf) > 0) ? (LTE | raf) : raf;
+ raf = ((NR & raf) > 0) ? (NR | raf) : raf;
return raf;
}
@@ -274,83 +275,78 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static int getNetworkTypeFromRaf(int raf) {
- int type;
-
raf = getAdjustedRaf(raf);
switch (raf) {
case (GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_WCDMA_PREF;
- break;
+ return RILConstants.NETWORK_MODE_WCDMA_PREF;
case GSM:
- type = RILConstants.NETWORK_MODE_GSM_ONLY;
- break;
+ return RILConstants.NETWORK_MODE_GSM_ONLY;
case WCDMA:
- type = RILConstants.NETWORK_MODE_WCDMA_ONLY;
- break;
+ return RILConstants.NETWORK_MODE_WCDMA_ONLY;
case (CDMA | EVDO):
- type = RILConstants.NETWORK_MODE_CDMA;
- break;
+ return RILConstants.NETWORK_MODE_CDMA;
case (LTE | CDMA | EVDO):
- type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
- break;
+ return RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
case (LTE | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
case (LTE | CDMA | EVDO | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
case LTE:
- type = RILConstants.NETWORK_MODE_LTE_ONLY;
- break;
+ return RILConstants.NETWORK_MODE_LTE_ONLY;
case (LTE | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_WCDMA;
case CDMA:
- type = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
- break;
+ return RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
case EVDO:
- type = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
- break;
+ return RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
case (GSM | WCDMA | CDMA | EVDO):
- type = RILConstants.NETWORK_MODE_GLOBAL;
- break;
+ return RILConstants.NETWORK_MODE_GLOBAL;
case RAF_TD_SCDMA:
- type = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
- break;
+ return RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
case (RAF_TD_SCDMA | WCDMA):
- type = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
case (LTE | RAF_TD_SCDMA):
- type = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_TDSCDMA;
case (RAF_TD_SCDMA | GSM):
- type = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
- break;
+ return RILConstants.NETWORK_MODE_TDSCDMA_GSM;
case (LTE | RAF_TD_SCDMA | GSM):
- type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
- break;
+ return RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
case (RAF_TD_SCDMA | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
case (LTE | RAF_TD_SCDMA | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
case (LTE | RAF_TD_SCDMA | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
case (RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
case (LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
- type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
- break;
+ return RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+ case (NR):
+ return RILConstants.NETWORK_MODE_NR_ONLY;
+ case (NR | LTE):
+ return RILConstants.NETWORK_MODE_NR_LTE;
+ case (NR | LTE | CDMA | EVDO):
+ return RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO;
+ case (NR | LTE | GSM | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA;
+ case (NR | LTE | CDMA | EVDO | GSM | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA;
+ case (NR | LTE | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_WCDMA;
+ case (NR | LTE | RAF_TD_SCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA;
+ case (NR | LTE | RAF_TD_SCDMA | GSM):
+ return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM;
+ case (NR | LTE | RAF_TD_SCDMA | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA;
+ case (NR | LTE | RAF_TD_SCDMA | GSM | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA;
+ case (NR | LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
+ return RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
default:
- type = RILConstants.PREFERRED_NETWORK_MODE ;
- break;
+ return RILConstants.PREFERRED_NETWORK_MODE;
}
-
- return type;
}
public static int singleRafTypeFromString(String rafString) {
@@ -377,6 +373,7 @@
case "EVDO": return EVDO;
case "WCDMA": return WCDMA;
case "LTE_CA": return RAF_LTE_CA;
+ case "NR": return RAF_NR;
default: return RAF_UNKNOWN;
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 10647e6..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;
@@ -169,7 +170,8 @@
RIL_RADIO_TECHNOLOGY_GSM,
RIL_RADIO_TECHNOLOGY_TD_SCDMA,
RIL_RADIO_TECHNOLOGY_IWLAN,
- RIL_RADIO_TECHNOLOGY_LTE_CA})
+ RIL_RADIO_TECHNOLOGY_LTE_CA,
+ RIL_RADIO_TECHNOLOGY_NR})
public @interface RilRadioTechnology {}
/**
* Available radio technologies for GSM, UMTS and CDMA.
@@ -538,7 +540,7 @@
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public int getDataRegState() {
return mDataRegState;
}
@@ -1358,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
*/
@@ -1533,7 +1547,6 @@
}
}
-
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @TelephonyManager.NetworkType int getDataNetworkType() {
@@ -1618,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/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 91375bc..d2ae106 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -85,6 +85,7 @@
CellSignalStrengthWcdma mWcdma;
CellSignalStrengthTdscdma mTdscdma;
CellSignalStrengthLte mLte;
+ CellSignalStrengthNr mNr;
/**
* Create a new SignalStrength from a intent notifier Bundle
@@ -116,7 +117,7 @@
public SignalStrength() {
this(new CellSignalStrengthCdma(), new CellSignalStrengthGsm(),
new CellSignalStrengthWcdma(), new CellSignalStrengthTdscdma(),
- new CellSignalStrengthLte());
+ new CellSignalStrengthLte(), new CellSignalStrengthNr());
}
/**
@@ -129,12 +130,14 @@
@NonNull CellSignalStrengthGsm gsm,
@NonNull CellSignalStrengthWcdma wcdma,
@NonNull CellSignalStrengthTdscdma tdscdma,
- @NonNull CellSignalStrengthLte lte) {
+ @NonNull CellSignalStrengthLte lte,
+ @NonNull CellSignalStrengthNr nr) {
mCdma = cdma;
mGsm = gsm;
mWcdma = wcdma;
mTdscdma = tdscdma;
mLte = lte;
+ mNr = nr;
}
/**
@@ -147,7 +150,8 @@
new CellSignalStrengthGsm(signalStrength.gw),
new CellSignalStrengthWcdma(),
new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte));
+ new CellSignalStrengthLte(signalStrength.lte),
+ new CellSignalStrengthNr());
}
/**
@@ -160,7 +164,23 @@
new CellSignalStrengthGsm(signalStrength.gsm),
new CellSignalStrengthWcdma(signalStrength.wcdma),
new CellSignalStrengthTdscdma(signalStrength.tdScdma),
- new CellSignalStrengthLte(signalStrength.lte));
+ new CellSignalStrengthLte(signalStrength.lte),
+ new CellSignalStrengthNr());
+ }
+
+ /**
+ * Constructor for Radio HAL V1.4.
+ *
+ * @param signalStrength signal strength reported from modem.
+ * @hide
+ */
+ public SignalStrength(android.hardware.radio.V1_4.SignalStrength signalStrength) {
+ this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
+ new CellSignalStrengthGsm(signalStrength.gsm),
+ new CellSignalStrengthWcdma(signalStrength.wcdma),
+ new CellSignalStrengthTdscdma(signalStrength.tdscdma),
+ new CellSignalStrengthLte(signalStrength.lte),
+ new CellSignalStrengthNr(signalStrength.nr));
}
private CellSignalStrength getPrimary() {
@@ -171,6 +191,7 @@
if (mTdscdma.isValid()) return mTdscdma;
if (mWcdma.isValid()) return mWcdma;
if (mGsm.isValid()) return mGsm;
+ if (mNr.isValid()) return mNr;
return mLte;
}
@@ -200,6 +221,7 @@
if (mTdscdma.isValid()) cssList.add(mTdscdma);
if (mWcdma.isValid()) cssList.add(mWcdma);
if (mGsm.isValid()) cssList.add(mGsm);
+ if (mNr.isValid()) cssList.add(mNr);
return cssList;
}
@@ -210,6 +232,7 @@
mWcdma.updateLevel(cc, ss);
mTdscdma.updateLevel(cc, ss);
mLte.updateLevel(cc, ss);
+ mNr.updateLevel(cc, ss);
}
/**
@@ -234,6 +257,7 @@
mWcdma = new CellSignalStrengthWcdma(s.mWcdma);
mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma);
mLte = new CellSignalStrengthLte(s.mLte);
+ mNr = new CellSignalStrengthNr(s.mNr);
}
/**
@@ -250,6 +274,7 @@
mWcdma = in.readParcelable(CellSignalStrengthWcdma.class.getClassLoader());
mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader());
mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
+ mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
}
/**
@@ -261,6 +286,7 @@
out.writeParcelable(mWcdma, flags);
out.writeParcelable(mTdscdma, flags);
out.writeParcelable(mLte, flags);
+ out.writeParcelable(mNr, flags);
}
/**
@@ -814,7 +840,7 @@
*/
@Override
public int hashCode() {
- return Objects.hash(mCdma, mGsm, mWcdma, mTdscdma, mLte);
+ return Objects.hash(mCdma, mGsm, mWcdma, mTdscdma, mLte, mNr);
}
/**
@@ -830,7 +856,8 @@
&& mGsm.equals(s.mGsm)
&& mWcdma.equals(s.mWcdma)
&& mTdscdma.equals(s.mTdscdma)
- && mLte.equals(s.mLte);
+ && mLte.equals(s.mLte)
+ && mNr.equals(s.mNr);
}
/**
@@ -844,6 +871,7 @@
.append(",mWcdma=").append(mWcdma)
.append(",mTdscdma=").append(mTdscdma)
.append(",mLte=").append(mLte)
+ .append(",mNr=").append(mNr)
.append(",primary=").append(getPrimary().getClass().getSimpleName())
.append("}")
.toString();
@@ -866,6 +894,7 @@
mWcdma = m.getParcelable("Wcdma");
mTdscdma = m.getParcelable("Tdscdma");
mLte = m.getParcelable("Lte");
+ mNr = m.getParcelable("Nr");
}
/**
@@ -885,6 +914,7 @@
m.putParcelable("Wcdma", mWcdma);
m.putParcelable("Tdscdma", mTdscdma);
m.putParcelable("Lte", mLte);
+ m.putParcelable("Nr", mNr);
}
/**
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..148563a 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 */
@@ -349,41 +349,30 @@
* Returns 0 if none of voice, sms, data is not supported
* Returns 1 for Single standby mode (Single SIM functionality)
* Returns 2 for Dual standby mode.(Dual SIM functionality)
+ * Returns 3 for Tri standby mode.(Tri SIM functionality)
*/
public int getPhoneCount() {
- int phoneCount = 1;
- switch (getMultiSimConfiguration()) {
- case UNKNOWN:
- // if voice or sms or data is supported, return 1 otherwise 0
- if (isVoiceCapable() || isSmsCapable()) {
- phoneCount = 1;
- } else {
- // todo: try to clean this up further by getting rid of the nested conditions
- if (mContext == null) {
- phoneCount = 1;
- } else {
- // check for data support
- ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- if (cm == null) {
- phoneCount = 1;
- } else {
- if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
- phoneCount = 1;
- } else {
- phoneCount = 0;
- }
- }
- }
+ int phoneCount = 0;
+
+ // check for voice and data support, 0 if not supported
+ if (!isVoiceCapable() && !isSmsCapable()) {
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ if (cm != null) {
+ if (!cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) {
+ return phoneCount;
}
- break;
- case DSDS:
- case DSDA:
- phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
- break;
- case TSTS:
- phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
- break;
+ }
+ }
+
+ phoneCount = 1;
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ phoneCount = telephony.getNumOfActiveSims();
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getNumOfActiveSims RemoteException", ex);
}
return phoneCount;
}
@@ -1352,6 +1341,38 @@
@SystemApi
public static final long MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS = 60000;
+ /**
+ * Intent sent when an error occurs that debug tools should log and possibly take further
+ * action such as capturing vendor-specific logs.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
+
+ /**
+ * An arbitrary ParcelUuid which should be consistent for each occurrence of the same event.
+ *
+ * This field must be included in all events.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
+
+ /**
+ * A freeform string description of the event.
+ *
+ * This field is optional for all events and as a guideline should not exceed 80 characters
+ * and should be as short as possible to convey the essence of the event.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_DEBUG_EVENT_DESCRIPTION =
+ "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
+
//
//
// Device Info
@@ -3117,14 +3138,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 +3153,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>();
}
}
@@ -6241,197 +6268,258 @@
NETWORK_MODE_LTE_TDSCDMA_WCDMA,
NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA,
NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA,
- NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
+ NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_NR_ONLY,
+ NETWORK_MODE_NR_LTE,
+ NETWORK_MODE_NR_LTE_CDMA_EVDO,
+ NETWORK_MODE_NR_LTE_GSM_WCDMA,
+ NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA,
+ NETWORK_MODE_NR_LTE_WCDMA,
+ NETWORK_MODE_NR_LTE_TDSCDMA,
+ NETWORK_MODE_NR_LTE_TDSCDMA_GSM,
+ NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA,
+ NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA,
+ NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA
})
@Retention(RetentionPolicy.SOURCE)
public @interface PrefNetworkMode{}
/**
- * network mode is GSM/WCDMA (WCDMA preferred).
+ * Preferred network mode is GSM/WCDMA (WCDMA preferred).
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_WCDMA_PREF = RILConstants.NETWORK_MODE_WCDMA_PREF;
/**
- * network mode is GSM only.
+ * Preferred network mode is GSM only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_GSM_ONLY = RILConstants.NETWORK_MODE_GSM_ONLY;
/**
- * network mode is WCDMA only.
+ * Preferred network mode is WCDMA only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_WCDMA_ONLY = RILConstants.NETWORK_MODE_WCDMA_ONLY;
/**
- * network mode is GSM/WCDMA (auto mode, according to PRL).
+ * Preferred network mode is GSM/WCDMA (auto mode, according to PRL).
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_GSM_UMTS = RILConstants.NETWORK_MODE_GSM_UMTS;
/**
- * network mode is CDMA and EvDo (auto mode, according to PRL).
+ * Preferred network mode is CDMA and EvDo (auto mode, according to PRL).
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA;
/**
- * network mode is CDMA only.
+ * Preferred network mode is CDMA only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO;
/**
- * network mode is EvDo only.
+ * Preferred network mode is EvDo only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA;
/**
- * network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL).
+ * Preferred network mode is GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL).
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_GLOBAL = RILConstants.NETWORK_MODE_GLOBAL;
/**
- * network mode is LTE, CDMA and EvDo.
+ * Preferred network mode is LTE, CDMA and EvDo.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO;
/**
- * preferred network mode is LTE, GSM/WCDMA.
+ * Preferred network mode is LTE, GSM/WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_GSM_WCDMA;
/**
- * network mode is LTE, CDMA, EvDo, GSM/WCDMA.
+ * Preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA =
RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA;
/**
- * network mode is LTE Only.
+ * Preferred network mode is LTE Only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_ONLY = RILConstants.NETWORK_MODE_LTE_ONLY;
/**
- * network mode is LTE/WCDMA.
+ * Preferred network mode is LTE/WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_WCDMA = RILConstants.NETWORK_MODE_LTE_WCDMA;
/**
- * network mode is TD-SCDMA only.
+ * Preferred network mode is TD-SCDMA only.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_TDSCDMA_ONLY = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
/**
- * network mode is TD-SCDMA and WCDMA.
+ * Preferred network mode is TD-SCDMA and WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_TDSCDMA_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
/**
- * network mode is TD-SCDMA and LTE.
+ * Preferred network mode is TD-SCDMA and LTE.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_TDSCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
/**
- * network mode is TD-SCDMA and GSM.
+ * Preferred network mode is TD-SCDMA and GSM.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_TDSCDMA_GSM = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
/**
- * network mode is TD-SCDMA,GSM and LTE.
+ * Preferred network mode is TD-SCDMA,GSM and LTE.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_TDSCDMA_GSM =
RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
/**
- * network mode is TD-SCDMA, GSM/WCDMA.
+ * Preferred network mode is TD-SCDMA, GSM/WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_TDSCDMA_GSM_WCDMA =
RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
/**
- * network mode is TD-SCDMA, WCDMA and LTE.
+ * Preferred network mode is TD-SCDMA, WCDMA and LTE.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_TDSCDMA_WCDMA =
RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
/**
- * network mode is TD-SCDMA, GSM/WCDMA and LTE.
+ * Preferred network mode is TD-SCDMA, GSM/WCDMA and LTE.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA =
RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
/**
- * network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA.
+ * Preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
-
/**
- * network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo.
+ * Preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo.
* @hide
*/
- @SystemApi
public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
/**
+ * Preferred network mode is NR 5G only.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_ONLY = RILConstants.NETWORK_MODE_NR_ONLY;
+
+ /**
+ * Preferred network mode is NR 5G, LTE.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE = RILConstants.NETWORK_MODE_NR_LTE;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, CDMA and EvDo.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_CDMA_EVDO =
+ RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, GSM and WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, CDMA, EvDo, GSM and WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE and WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_WCDMA = RILConstants.NETWORK_MODE_NR_LTE_WCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE and TDSCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_TDSCDMA = RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, TD-SCDMA and GSM.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_TDSCDMA_GSM =
+ RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, TD-SCDMA, WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA =
+ RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, TD-SCDMA, GSM and WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA;
+
+ /**
+ * Preferred network mode is NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA.
+ * @hide
+ */
+ public static final int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA =
+ RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+
+ /**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
*
* <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return the preferred network type.
* @hide
*/
- @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
- @SystemApi
+ @RequiresPermission((android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE))
+ @UnsupportedAppUsage
public @PrefNetworkMode int getPreferredNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
- if (telephony != null)
+ if (telephony != null) {
return telephony.getPreferredNetworkType(subId);
+ }
} catch (RemoteException ex) {
Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
} catch (NullPointerException ex) {
@@ -7802,9 +7890,7 @@
* support for the feature and device firmware support.
*
* @return {@code true} if the device and carrier both support RTT, {@code false} otherwise.
- * @hide
*/
- @TestApi
public boolean isRttSupported() {
try {
ITelephony telephony = getITelephony();
@@ -8440,12 +8526,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 +8552,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 +9034,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 +9047,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 +9140,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);
}
@@ -9479,10 +9599,10 @@
*
* <p>
* Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isOpportunisticNetworkEnabled() {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
boolean isEnabled = false;
@@ -9863,12 +9983,17 @@
* Get preferred opportunistic data subscription Id
*
* <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}),
- * or has permission {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}.
+ * or has either READ_PRIVILEGED_PHONE_STATE
+ * or {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission.
* @return subId preferred opportunistic subscription id or
* {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} if there are no preferred
* subscription id
*
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE
+ })
public int getPreferredOpportunisticDataSubscription() {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -9941,4 +10066,120 @@
}
return ret;
}
+
+ /**
+ * Indicate if the user is allowed to use multiple SIM cards at the same time to register
+ * on the network (e.g. Dual Standby or Dual Active) when the device supports it, or if the
+ * usage is restricted. This API is used to prevent usage of multiple SIM card, based on
+ * policies of the carrier.
+ * <p>Note: the API does not prevent access to the SIM cards for operations that don't require
+ * access to the network.
+ *
+ * @param isMultisimCarrierRestricted true if usage of multiple SIMs is restricted, false
+ * otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ service.setMultisimCarrierRestriction(isMultisimCarrierRestricted);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "setMultisimCarrierRestriction RemoteException", e);
+ }
+ }
+
+ /**
+ * Returns if the usage of multiple SIM cards at the same time to register on the network
+ * (e.g. Dual Standby or Dual Active) is restricted.
+ *
+ * @return true if usage of multiple SIMs is restricted, false otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isMultisimCarrierRestricted() {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.isMultisimCarrierRestricted();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "isMultisimCarrierRestricted RemoteException", e);
+ }
+ return true;
+ }
+
+ /**
+ * Broadcast intent action for network country code changes.
+ *
+ * <p>
+ * The {@link #EXTRA_NETWORK_COUNTRY} extra indicates the country code of the current
+ * network returned by {@link #getNetworkCountryIso()}.
+ *
+ * @see #EXTRA_NETWORK_COUNTRY
+ * @see #getNetworkCountryIso()
+ */
+ public static final String ACTION_NETWORK_COUNTRY_CHANGED =
+ "android.telephony.action.NETWORK_COUNTRY_CHANGED";
+
+ /**
+ * The extra used with an {@link #ACTION_NETWORK_COUNTRY_CHANGED} to specify the
+ * the country code in ISO 3166 format.
+ * <p class="note">
+ * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
+ */
+ public static final String EXTRA_NETWORK_COUNTRY =
+ "android.telephony.extra.NETWORK_COUNTRY";
+ /**
+ * Switch configs to enable multi-sim or switch back to single-sim
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ * @param numOfSims number of live SIMs we want to switch to
+ * @throws android.os.RemoteException
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void switchMultiSimConfig(int numOfSims) {
+ //only proceed if multi-sim is not restricted
+ if (isMultisimCarrierRestricted()) {
+ Rlog.e(TAG, "switchMultiSimConfig not possible. It is restricted.");
+ return;
+ }
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.switchMultiSimConfig(numOfSims);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "switchMultiSimConfig RemoteException", ex);
+ }
+ }
+
+ /**
+ * Get whether reboot is required or not after making changes to modem configurations.
+ * @Return {@code True} if reboot is required after making changes to modem configurations,
+ * otherwise return {@code False}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isRebootRequiredForModemConfigChange() {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.isRebootRequiredForModemConfigChange();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "isRebootRequiredForModemConfigChange RemoteException", e);
+ }
+ return false;
+ }
}
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 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/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 74d1e83..79572b9 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -157,7 +157,10 @@
@Nullable LinkProperties linkProperties,
@Nullable DataServiceCallback callback) {
// The default implementation is to return unsupported.
- callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
+ if (callback != null) {
+ callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED,
+ null);
+ }
}
/**
@@ -176,7 +179,9 @@
public void deactivateDataCall(int cid, @DeactivateDataReason int reason,
@Nullable DataServiceCallback callback) {
// The default implementation is to return unsupported.
- callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ if (callback != null) {
+ callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ }
}
/**
@@ -190,7 +195,10 @@
public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
@Nullable DataServiceCallback callback) {
// The default implementation is to return unsupported.
- callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ if (callback != null) {
+ callback.onSetInitialAttachApnComplete(
+ DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ }
}
/**
@@ -206,7 +214,9 @@
public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
@Nullable DataServiceCallback callback) {
// The default implementation is to return unsupported.
- callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ if (callback != null) {
+ callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
+ }
}
/**
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 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/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a5c0442..40c6f70 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -253,7 +253,7 @@
public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
private final Context mContext;
- private final int mCardId;
+ private int mCardId;
/** @hide */
public EuiccManager(Context context) {
@@ -291,7 +291,7 @@
public boolean isEnabled() {
// In the future, this may reach out to IEuiccController (if non-null) to check any dynamic
// restrictions.
- return getIEuiccController() != null && mCardId != TelephonyManager.INVALID_CARD_ID;
+ return getIEuiccController() != null;
}
/**
@@ -301,15 +301,15 @@
* current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
* access to the EID of another eUICC.
*
- * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
+ * @return the EID. May be null if the eUICC is not ready.
*/
@Nullable
public String getEid() {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
return null;
}
try {
- return getIEuiccController().getEid(mCardId);
+ return getIEuiccController().getEid(mCardId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -320,15 +320,15 @@
*
* <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
*
- * @return the status of eUICC OTA. If {@link #isEnabled()} is false or the eUICC is not ready,
- * {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned.
+ * @return the status of eUICC OTA. If the eUICC is not ready,
+ * {@link OtaStatus#EUICC_OTA_STATUS_UNAVAILABLE} will be returned.
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public int getOtaStatus() {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
}
try {
@@ -347,6 +347,15 @@
* Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
* returned in the callback intent to prompt the user to accept the download.
*
+ * <p>On a multi-active SIM device, requires the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app
+ * only if the targeted eUICC does not currently have an active subscription or the calling app
+ * is authorized to manage the active subscription on the target eUICC, and the calling app is
+ * authorized to manage any active subscription on any SIM. Without it, an
+ * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+ * intent to prompt the user to accept the download. The caller should also be authorized to
+ * manage the subscription to be downloaded.
+ *
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
* @param callbackIntent a PendingIntent to launch when the operation completes.
@@ -354,7 +363,7 @@
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void downloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -416,7 +425,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
PendingIntent callbackIntent =
resolutionIntent.getParcelableExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
@@ -453,7 +462,7 @@
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -483,7 +492,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -498,12 +507,11 @@
/**
* Returns information about the eUICC chip/device.
*
- * @return the {@link EuiccInfo}. May be null if {@link #isEnabled()} is false or the eUICC is
- * not ready.
+ * @return the {@link EuiccInfo}. May be null if the eUICC is not ready.
*/
@Nullable
public EuiccInfo getEuiccInfo() {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
return null;
}
try {
@@ -528,7 +536,7 @@
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -549,14 +557,26 @@
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
* intent to prompt the user to accept the download.
*
+ * <p>On a multi-active SIM device, requires the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app
+ * only if the targeted eUICC does not currently have an active subscription or the calling app
+ * is authorized to manage the active subscription on the target eUICC, and the calling app is
+ * authorized to manage any active subscription on any SIM. Without it, an
+ * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+ * intent to prompt the user to accept the download. The caller should also be authorized to
+ * manage the subscription to be enabled.
+ *
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
- * current profile without activating another profile to replace it.
+ * current profile without activating another profile to replace it. If it's a disable
+ * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS}
+ * permission, or the calling app must be authorized to manage the active subscription on
+ * the target eUICC.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -582,7 +602,7 @@
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
int subscriptionId, String nickname, PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -606,7 +626,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void eraseSubscriptions(PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -636,7 +656,7 @@
* @hide
*/
public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
- if (!isEnabled()) {
+ if (!refreshCardIdIfInvalid()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -647,6 +667,19 @@
}
}
+ private boolean refreshCardIdIfInvalid() {
+ if (!isEnabled()) {
+ return false;
+ }
+ // Refresh mCardId if it's invalid.
+ if (mCardId == TelephonyManager.INVALID_CARD_ID) {
+ TelephonyManager tm = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mCardId = tm.getCardIdForDefaultEuicc();
+ }
+ return true;
+ }
+
private static void sendUnavailableError(PendingIntent callbackIntent) {
try {
callbackIntent.send(EMBEDDED_SUBSCRIPTION_RESULT_ERROR);
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/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
new file mode 100644
index 0000000..ac4d17a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -0,0 +1,113 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.text.TextUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This class defines an IMS-related exception that has been thrown while interacting with a
+ * device or carrier provided ImsService implementation.
+ * @hide
+ */
+@SystemApi
+public class ImsException extends Exception {
+
+ /**
+ * The operation has failed due to an unknown or unspecified error.
+ */
+ public static final int CODE_ERROR_UNSPECIFIED = 0;
+ /**
+ * The operation has failed because there is no {@link ImsService} available to service it. This
+ * may be due to an {@link ImsService} crash or other illegal state.
+ * <p>
+ * This is a temporary error and the operation may be retried until the connection to the
+ * {@link ImsService} is restored.
+ */
+ public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1;
+
+ /**
+ * This device or carrier configuration does not support IMS for this subscription.
+ * <p>
+ * This is a permanent configuration error and there should be no retry.
+ */
+ public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2;
+
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CODE_ERROR_", value = {
+ CODE_ERROR_UNSPECIFIED,
+ CODE_ERROR_SERVICE_UNAVAILABLE,
+ CODE_ERROR_UNSUPPORTED_OPERATION
+ })
+ public @interface ImsErrorCode {}
+
+ private int mCode = CODE_ERROR_UNSPECIFIED;
+
+ /**
+ * A new {@link ImsException} with an unspecified {@link ImsErrorCode} code.
+ * @param message an optional message to detail the error condition more specifically.
+ */
+ public ImsException(@Nullable String message) {
+ super(getMessage(message, CODE_ERROR_UNSPECIFIED));
+ }
+
+ /**
+ * A new {@link ImsException} that includes an {@link ImsErrorCode} error code.
+ * @param message an optional message to detail the error condition more specifically.
+ */
+ public ImsException(@Nullable String message, @ImsErrorCode int code) {
+ super(getMessage(message, code));
+ mCode = code;
+ }
+
+ /**
+ * A new {@link ImsException} that includes an {@link ImsErrorCode} error code and a
+ * {@link Throwable} that contains the original error that was thrown to lead to this Exception.
+ * @param message an optional message to detail the error condition more specifically.
+ * @param cause the {@link Throwable} that caused this {@link ImsException} to be created.
+ */
+ public ImsException(@Nullable String message, @ImsErrorCode int code, Throwable cause) {
+ super(getMessage(message, code), cause);
+ mCode = code;
+ }
+
+ /**
+ * @return the IMS Error code that is associated with this {@link ImsException}.
+ */
+ public @ImsErrorCode int getCode() {
+ return mCode;
+ }
+
+ private static String getMessage(String message, int code) {
+ StringBuilder builder;
+ if (!TextUtils.isEmpty(message)) {
+ builder = new StringBuilder(message);
+ builder.append(" (code: ");
+ builder.append(code);
+ builder.append(")");
+ return builder.toString();
+ } else {
+ return "code: " + code;
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 9414abd..eb99d5d 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -54,7 +54,7 @@
* registration and MmTel capability status callbacks, as well as query/modify user settings for the
* associated subscription.
*
- * @see #createForSubscriptionId(Context, int)
+ * @see #createForSubscriptionId(int)
* @hide
*/
@SystemApi
@@ -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;
/**
@@ -317,15 +315,12 @@
/**
* Create an instance of ImsManager for the subscription id specified.
*
- * @param context The context to create this ImsMmTelManager instance within.
* @param subId The ID of the subscription that this ImsMmTelManager will use.
* @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
- * @throws IllegalArgumentException if the subscription is invalid or
- * the subscription ID is not an active subscription.
+ * @throws IllegalArgumentException if the subscription is invalid.
*/
- public static ImsMmTelManager createForSubscriptionId(Context context, int subId) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)
- || !getSubscriptionManager(context).isActiveSubscriptionId(subId)) {
+ public static ImsMmTelManager createForSubscriptionId(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
}
@@ -333,7 +328,7 @@
}
/**
- * Only visible for testing, use {@link #createForSubscriptionId(Context, int)} instead.
+ * Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
* @hide
*/
@VisibleForTesting
@@ -343,7 +338,7 @@
/**
* Registers a {@link RegistrationCallback} with the system, which will provide registration
- * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
+ * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
* events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
@@ -356,13 +351,14 @@
* @throws IllegalArgumentException if the subscription associated with this callback is not
* active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
* {@link CapabilityCallback} callback.
- * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * @throws ImsException if the subscription associated with this callback is valid, but
* the {@link ImsService} associated with the subscription is not available. This can happen if
- * the service crashed, for example.
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
- @NonNull RegistrationCallback c) {
+ @NonNull RegistrationCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
@@ -374,6 +370,8 @@
getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } catch (IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
@@ -405,7 +403,7 @@
/**
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
* availability updates for the subscription specified in
- * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+ * {@link #createForSubscriptionId(int)}. The method {@link #isAvailable(int, int)}
* can also be used to query this information at any time.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
@@ -421,13 +419,14 @@
* @throws IllegalArgumentException if the subscription associated with this callback is not
* active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
* {@link CapabilityCallback} callback.
- * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * @throws ImsException if the subscription associated with this callback is valid, but
* the {@link ImsService} associated with the subscription is not available. This can happen if
- * the service crashed, for example.
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull CapabilityCallback c) {
+ @NonNull CapabilityCallback c) throws ImsException {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
@@ -439,6 +438,8 @@
getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } catch (IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
@@ -798,14 +799,6 @@
}
}
- private static SubscriptionManager getSubscriptionManager(Context context) {
- SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
- if (manager == null) {
- throw new RuntimeException("Could not find SubscriptionManager.");
- }
- return manager;
- }
-
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
ServiceManager.getService(Context.TELEPHONY_SERVICE));
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 4d95e55..d8d2d9e 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -465,7 +465,7 @@
public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511;
/**
- * Upgrade Downgrade request cacncelled by the user who initiated it
+ * Upgrade Downgrade request cancelled by the user who initiated it
*/
public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512;
@@ -887,6 +887,185 @@
public static final int CODE_OEM_CAUSE_15 = 0xf00f;
/**
+ * @hide
+ */
+ @IntDef(value = {
+ CODE_UNSPECIFIED,
+ CODE_LOCAL_ILLEGAL_ARGUMENT,
+ CODE_LOCAL_ILLEGAL_STATE,
+ CODE_LOCAL_INTERNAL_ERROR,
+ CODE_LOCAL_IMS_SERVICE_DOWN,
+ CODE_LOCAL_NO_PENDING_CALL,
+ CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+ CODE_LOCAL_POWER_OFF,
+ CODE_LOCAL_LOW_BATTERY,
+ CODE_LOCAL_NETWORK_NO_SERVICE,
+ CODE_LOCAL_NETWORK_NO_LTE_COVERAGE,
+ CODE_LOCAL_NETWORK_ROAMING,
+ CODE_LOCAL_NETWORK_IP_CHANGED,
+ CODE_LOCAL_SERVICE_UNAVAILABLE,
+ CODE_LOCAL_NOT_REGISTERED,
+ CODE_LOCAL_CALL_EXCEEDED,
+ CODE_LOCAL_CALL_BUSY,
+ CODE_LOCAL_CALL_DECLINE,
+ CODE_LOCAL_CALL_VCC_ON_PROGRESSING,
+ CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
+ CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
+ CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
+ CODE_LOCAL_CALL_TERMINATED,
+ CODE_LOCAL_HO_NOT_FEASIBLE,
+ CODE_TIMEOUT_1XX_WAITING,
+ CODE_TIMEOUT_NO_ANSWER,
+ CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE,
+ CODE_CALL_BARRED,
+ CODE_FDN_BLOCKED,
+ CODE_IMEI_NOT_ACCEPTED,
+ CODE_DIAL_MODIFIED_TO_USSD,
+ CODE_DIAL_MODIFIED_TO_SS,
+ CODE_DIAL_MODIFIED_TO_DIAL,
+ CODE_DIAL_MODIFIED_TO_DIAL_VIDEO,
+ CODE_DIAL_VIDEO_MODIFIED_TO_DIAL,
+ CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO,
+ CODE_DIAL_VIDEO_MODIFIED_TO_SS,
+ CODE_DIAL_VIDEO_MODIFIED_TO_USSD,
+ CODE_SIP_REDIRECTED,
+ CODE_SIP_BAD_REQUEST,
+ CODE_SIP_FORBIDDEN,
+ CODE_SIP_NOT_FOUND,
+ CODE_SIP_NOT_SUPPORTED,
+ CODE_SIP_REQUEST_TIMEOUT,
+ CODE_SIP_TEMPRARILY_UNAVAILABLE,
+ CODE_SIP_BAD_ADDRESS,
+ CODE_SIP_BUSY,
+ CODE_SIP_REQUEST_CANCELLED,
+ CODE_SIP_NOT_ACCEPTABLE,
+ CODE_SIP_NOT_REACHABLE,
+ CODE_SIP_CLIENT_ERROR,
+ CODE_SIP_TRANSACTION_DOES_NOT_EXIST,
+ CODE_SIP_SERVER_INTERNAL_ERROR,
+ CODE_SIP_SERVICE_UNAVAILABLE,
+ CODE_SIP_SERVER_TIMEOUT,
+ CODE_SIP_SERVER_ERROR,
+ CODE_SIP_USER_REJECTED,
+ CODE_SIP_GLOBAL_ERROR,
+ CODE_EMERGENCY_TEMP_FAILURE,
+ CODE_EMERGENCY_PERM_FAILURE,
+ CODE_SIP_USER_MARKED_UNWANTED,
+ CODE_SIP_METHOD_NOT_ALLOWED,
+ CODE_SIP_PROXY_AUTHENTICATION_REQUIRED,
+ CODE_SIP_REQUEST_ENTITY_TOO_LARGE,
+ CODE_SIP_REQUEST_URI_TOO_LARGE,
+ CODE_SIP_EXTENSION_REQUIRED,
+ CODE_SIP_INTERVAL_TOO_BRIEF,
+ CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST,
+ CODE_SIP_LOOP_DETECTED,
+ CODE_SIP_TOO_MANY_HOPS,
+ CODE_SIP_AMBIGUOUS,
+ CODE_SIP_REQUEST_PENDING,
+ CODE_SIP_UNDECIPHERABLE,
+ CODE_MEDIA_INIT_FAILED,
+ CODE_MEDIA_NO_DATA,
+ CODE_MEDIA_NOT_ACCEPTABLE,
+ CODE_MEDIA_UNSPECIFIED,
+ CODE_USER_TERMINATED,
+ CODE_USER_NOANSWER,
+ CODE_USER_IGNORE,
+ CODE_USER_DECLINE,
+ CODE_LOW_BATTERY,
+ CODE_BLACKLISTED_CALL_ID,
+ CODE_USER_TERMINATED_BY_REMOTE,
+ CODE_USER_REJECTED_SESSION_MODIFICATION,
+ CODE_USER_CANCELLED_SESSION_MODIFICATION,
+ CODE_SESSION_MODIFICATION_FAILED,
+ CODE_UT_NOT_SUPPORTED,
+ CODE_UT_SERVICE_UNAVAILABLE,
+ CODE_UT_OPERATION_NOT_ALLOWED,
+ CODE_UT_NETWORK_ERROR,
+ CODE_UT_CB_PASSWORD_MISMATCH,
+ CODE_UT_SS_MODIFIED_TO_DIAL,
+ CODE_UT_SS_MODIFIED_TO_USSD,
+ CODE_UT_SS_MODIFIED_TO_SS,
+ CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO,
+ CODE_ECBM_NOT_SUPPORTED,
+ CODE_MULTIENDPOINT_NOT_SUPPORTED,
+ CODE_REGISTRATION_ERROR,
+ CODE_ANSWERED_ELSEWHERE,
+ CODE_CALL_PULL_OUT_OF_SYNC,
+ CODE_CALL_END_CAUSE_CALL_PULL,
+ CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
+ CODE_REJECTED_ELSEWHERE,
+ CODE_SUPP_SVC_FAILED,
+ CODE_SUPP_SVC_CANCELLED,
+ CODE_SUPP_SVC_REINVITE_COLLISION,
+ CODE_IWLAN_DPD_FAILURE,
+ CODE_EPDG_TUNNEL_ESTABLISH_FAILURE,
+ CODE_EPDG_TUNNEL_REKEY_FAILURE,
+ CODE_EPDG_TUNNEL_LOST_CONNECTION,
+ CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
+ CODE_REMOTE_CALL_DECLINE,
+ CODE_DATA_LIMIT_REACHED,
+ CODE_DATA_DISABLED,
+ CODE_WIFI_LOST,
+ CODE_IKEV2_AUTH_FAILURE,
+ CODE_RADIO_OFF,
+ CODE_NO_VALID_SIM,
+ CODE_RADIO_INTERNAL_ERROR,
+ CODE_NETWORK_RESP_TIMEOUT,
+ CODE_NETWORK_REJECT,
+ CODE_RADIO_ACCESS_FAILURE,
+ CODE_RADIO_LINK_FAILURE,
+ CODE_RADIO_LINK_LOST,
+ CODE_RADIO_UPLINK_FAILURE,
+ CODE_RADIO_SETUP_FAILURE,
+ CODE_RADIO_RELEASE_NORMAL,
+ CODE_RADIO_RELEASE_ABNORMAL,
+ CODE_ACCESS_CLASS_BLOCKED,
+ CODE_NETWORK_DETACH,
+ CODE_SIP_ALTERNATE_EMERGENCY_CALL,
+ CODE_UNOBTAINABLE_NUMBER,
+ CODE_NO_CSFB_IN_CS_ROAM,
+ CODE_REJECT_UNKNOWN,
+ CODE_REJECT_ONGOING_CALL_WAITING_DISABLED,
+ CODE_REJECT_CALL_ON_OTHER_SUB,
+ CODE_REJECT_1X_COLLISION,
+ CODE_REJECT_SERVICE_NOT_REGISTERED,
+ CODE_REJECT_CALL_TYPE_NOT_ALLOWED,
+ CODE_REJECT_ONGOING_E911_CALL,
+ CODE_REJECT_ONGOING_CALL_SETUP,
+ CODE_REJECT_MAX_CALL_LIMIT_REACHED,
+ CODE_REJECT_UNSUPPORTED_SIP_HEADERS,
+ CODE_REJECT_UNSUPPORTED_SDP_HEADERS,
+ CODE_REJECT_ONGOING_CALL_TRANSFER,
+ CODE_REJECT_INTERNAL_ERROR,
+ CODE_REJECT_QOS_FAILURE,
+ CODE_REJECT_ONGOING_HANDOVER,
+ CODE_REJECT_VT_TTY_NOT_ALLOWED,
+ CODE_REJECT_ONGOING_CALL_UPGRADE,
+ CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED,
+ CODE_REJECT_ONGOING_CONFERENCE_CALL,
+ CODE_REJECT_VT_AVPF_NOT_ALLOWED,
+ CODE_REJECT_ONGOING_ENCRYPTED_CALL,
+ CODE_REJECT_ONGOING_CS_CALL,
+ CODE_OEM_CAUSE_1,
+ CODE_OEM_CAUSE_2,
+ CODE_OEM_CAUSE_3,
+ CODE_OEM_CAUSE_4,
+ CODE_OEM_CAUSE_5,
+ CODE_OEM_CAUSE_6,
+ CODE_OEM_CAUSE_7,
+ CODE_OEM_CAUSE_8,
+ CODE_OEM_CAUSE_9,
+ CODE_OEM_CAUSE_10,
+ CODE_OEM_CAUSE_11,
+ CODE_OEM_CAUSE_12,
+ CODE_OEM_CAUSE_13,
+ CODE_OEM_CAUSE_14,
+ CODE_OEM_CAUSE_15
+ }, prefix = "CODE_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsCode {}
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
@@ -964,7 +1143,7 @@
/**
* @return an integer representing more information about the completion of an operation.
*/
- public int getCode() {
+ public @ImsCode int getCode() {
return mCode;
}
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index d37198a..204891b 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 {
@@ -113,15 +172,13 @@
/**
* Create a new {@link ProvisioningManager} for the subscription specified.
- * @param context The context that this manager will use.
+ *
* @param subId The ID of the subscription that this ProvisioningManager will use.
* @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
- * @throws IllegalArgumentException if the subscription is invalid or
- * the subscription ID is not an active subscription.
+ * @throws IllegalArgumentException if the subscription is invalid.
*/
- public static ProvisioningManager createForSubscriptionId(Context context, int subId) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)
- || !getSubscriptionManager(context).isActiveSubscriptionId(subId)) {
+ public static ProvisioningManager createForSubscriptionId(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
}
@@ -143,18 +200,21 @@
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @throws IllegalArgumentException if the subscription associated with this callback is not
* active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
- * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * @throws ImsException if the subscription associated with this callback is valid, but
* the {@link ImsService} associated with the subscription is not available. This can happen if
- * the service crashed, for example.
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
- @NonNull Callback callback) {
+ @NonNull Callback callback) throws ImsException {
callback.setExecutor(executor);
try {
getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } catch (IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
@@ -180,10 +240,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 +260,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 +281,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 +303,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,12 +321,53 @@
}
}
- private static SubscriptionManager getSubscriptionManager(Context context) {
- SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
- if (manager == null) {
- throw new RuntimeException("Could not find SubscriptionManager.");
+ /**
+ * 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();
}
- return manager;
+ }
+
+ /**
+ * 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 ITelephony getITelephony() {
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/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
index 77e36bb..603f4e6 100644
--- a/telephony/java/android/telephony/mbms/GroupCallCallback.java
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -57,7 +57,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- void onError(@GroupCallError int errorCode, @Nullable String message);
+ default void onError(@GroupCallError int errorCode, @Nullable String message) {}
/**
* Called to indicate this call has changed state.
@@ -65,8 +65,8 @@
* See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
* and {@link GroupCall#STATE_STALLED}.
*/
- void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
- @GroupCall.GroupCallStateChangeReason int reason);
+ default void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+ @GroupCall.GroupCallStateChangeReason int reason) {}
/**
* Broadcast Signal Strength updated.
@@ -78,5 +78,6 @@
* {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
* for this call due to timing, geography or popularity.
*/
- void onBroadcastSignalStrengthUpdated(@IntRange(from = -1, to = 4) int signalStrength);
+ default void onBroadcastSignalStrengthUpdated(
+ @IntRange(from = -1, to = 4) int signalStrength) {}
}
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
index 04e7ba1..ac7e172 100644
--- a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -57,7 +57,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- void onError(@GroupCallError int errorCode, @Nullable String message);
+ default void onError(@GroupCallError int errorCode, @Nullable String message) {}
/**
* Indicates that the list of currently available SAIs has been updated. The app may use this
@@ -70,8 +70,8 @@
* @param availableSais A list of lists of available SAIS in neighboring cells, where each list
* contains the available SAIs in an individual cell.
*/
- void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
- @NonNull List<List<Integer>> availableSais);
+ default void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
+ @NonNull List<List<Integer>> availableSais) {}
/**
* Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
@@ -85,7 +85,7 @@
* @param interfaceName The interface name for the data link.
* @param index The index for the data link.
*/
- void onServiceInterfaceAvailable(@NonNull String interfaceName, int index);
+ default void onServiceInterfaceAvailable(@NonNull String interfaceName, int index) {}
/**
* Called to indicate that the middleware has been initialized and is ready.
@@ -95,5 +95,5 @@
* delivered via {@link #onError(int, String)} with error code
* {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
*/
- void onMiddlewareReady();
+ default void onMiddlewareReady() {}
}
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/ImsException.java b/telephony/java/com/android/ims/ImsException.java
index f35e886..fea763e 100644
--- a/telephony/java/com/android/ims/ImsException.java
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -21,8 +21,10 @@
/**
* This class defines a general IMS-related exception.
*
+ * @deprecated Use {@link android.telephony.ims.ImsException} instead.
* @hide
*/
+@Deprecated
public class ImsException extends Exception {
/**
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/EncodeException.java b/telephony/java/com/android/internal/telephony/EncodeException.java
index 4e3fac1..cdc853e 100644
--- a/telephony/java/com/android/internal/telephony/EncodeException.java
+++ b/telephony/java/com/android/internal/telephony/EncodeException.java
@@ -22,6 +22,12 @@
* {@hide}
*/
public class EncodeException extends Exception {
+
+ private int mError = ERROR_UNENCODABLE;
+
+ public static final int ERROR_UNENCODABLE = 0;
+ public static final int ERROR_EXCEED_SIZE = 1;
+
public EncodeException() {
super();
}
@@ -31,9 +37,18 @@
super(s);
}
+ public EncodeException(String s, int error) {
+ super(s);
+ mError = error;
+ }
+
@UnsupportedAppUsage
public EncodeException(char c) {
super("Unencodable char: '" + c + "'");
}
+
+ public int getError() {
+ return mError;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index 84c0e64..a774cdc 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -388,7 +388,7 @@
* GSM extension table
* @return the encoded message
*
- * @throws EncodeException if String is too large to encode
+ * @throws EncodeException if String is too large to encode or any characters are unencodable
*/
@UnsupportedAppUsage
public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset,
@@ -402,7 +402,8 @@
}
septetCount += startingSeptetOffset;
if (septetCount > 255) {
- throw new EncodeException("Payload cannot exceed 255 septets");
+ throw new EncodeException(
+ "Payload cannot exceed 255 septets", EncodeException.ERROR_EXCEED_SIZE);
}
int byteCount = ((septetCount * 7) + 7) / 8;
byte[] ret = new byte[byteCount + 1]; // Include space for one byte length prefix.
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3dbebe8..322ce45 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -27,6 +27,7 @@
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsReasonInfo;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -58,5 +59,6 @@
void onCallAttributesChanged(in CallAttributes callAttributes);
void onEmergencyNumberListChanged(in Map emergencyNumberList);
void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
+ void onImsCallDisconnectCauseChanged(in ImsReasonInfo imsReasonInfo);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index db76e9e..c7061df 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,44 @@
int setImsProvisioningString(int subId, int key, String value);
/**
+ * Update Emergency Number List for Test Mode.
+ */
+ void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
+
+ /**
+ * Get the full emergency number list for Test Mode.
+ */
+ List<String> getEmergencyNumberListTestMode();
+
+ /**
* Enable or disable a logical modem stack associated with the slotIndex.
*/
boolean enableModemForSlot(int slotIndex, boolean enable);
+
+ /**
+ * Indicate if the enablement of multi SIM functionality is restricted.
+ * @hide
+ */
+ void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted);
+
+ /**
+ * Returns if the usage of multiple SIM cards at the same time is restricted.
+ * @hide
+ */
+ boolean isMultisimCarrierRestricted();
+
+ /**
+ * Switch configs to enable multi-sim or switch back to single-sim
+ * @hide
+ */
+ void switchMultiSimConfig(int numOfSims);
+ /**
+ * Get how many modems have been activated on the phone
+ * @hide
+ */
+ int getNumOfActiveSims();
+ /**
+ * Get if reboot is required upon altering modems configurations
+ */
+ boolean isRebootRequiredForModemConfigChange();
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2be1f41..e9eba32 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.telephony.CallQuality;
import android.telephony.CellInfo;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.PhoneCapability;
import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
@@ -84,4 +85,5 @@
void notifyRadioPowerStateChanged(in int state);
void notifyEmergencyNumberList();
void notifyCallQualityChanged(in CallQuality callQuality, int phoneId);
+ void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 599503c..77b7979 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -128,32 +128,108 @@
int OEM_ERROR_25 = 525;
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
- int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
- int NETWORK_MODE_GSM_ONLY = 1; /* GSM only */
- int NETWORK_MODE_WCDMA_ONLY = 2; /* WCDMA only */
- int NETWORK_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL)
- AVAILABLE Application Settings menu*/
- int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL)
- AVAILABLE Application Settings menu*/
- int NETWORK_MODE_CDMA_NO_EVDO = 5; /* CDMA only */
- int NETWORK_MODE_EVDO_NO_CDMA = 6; /* EvDo only */
- int NETWORK_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
- AVAILABLE Application Settings menu*/
- int NETWORK_MODE_LTE_CDMA_EVDO = 8; /* LTE, CDMA and EvDo */
- int NETWORK_MODE_LTE_GSM_WCDMA = 9; /* LTE, GSM/WCDMA */
- int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
- int NETWORK_MODE_LTE_ONLY = 11; /* LTE Only mode. */
- int NETWORK_MODE_LTE_WCDMA = 12; /* LTE/WCDMA */
- int NETWORK_MODE_TDSCDMA_ONLY = 13; /* TD-SCDMA only */
- int NETWORK_MODE_TDSCDMA_WCDMA = 14; /* TD-SCDMA and WCDMA */
- int NETWORK_MODE_LTE_TDSCDMA = 15; /* TD-SCDMA and LTE */
- int NETWORK_MODE_TDSCDMA_GSM = 16; /* TD-SCDMA and GSM */
- int NETWORK_MODE_LTE_TDSCDMA_GSM = 17; /* TD-SCDMA,GSM and LTE */
- int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18; /* TD-SCDMA, GSM/WCDMA */
- int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19; /* TD-SCDMA, WCDMA and LTE */
- int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; /* TD-SCDMA, GSM/WCDMA and LTE */
- int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; /*TD-SCDMA,EvDo,CDMA,GSM/WCDMA*/
- int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; /* TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo */
+ /** GSM, WCDMA (WCDMA preferred) */
+ int NETWORK_MODE_WCDMA_PREF = 0;
+
+ /** GSM only */
+ int NETWORK_MODE_GSM_ONLY = 1;
+
+ /** WCDMA only */
+ int NETWORK_MODE_WCDMA_ONLY = 2;
+
+ /** GSM, WCDMA (auto mode, according to PRL) */
+ int NETWORK_MODE_GSM_UMTS = 3;
+
+ /** CDMA and EvDo (auto mode, according to PRL) */
+ int NETWORK_MODE_CDMA = 4;
+
+ /** CDMA only */
+ int NETWORK_MODE_CDMA_NO_EVDO = 5;
+
+ /** EvDo only */
+ int NETWORK_MODE_EVDO_NO_CDMA = 6;
+
+ /** GSM, WCDMA, CDMA, and EvDo (auto mode, according to PRL) */
+ int NETWORK_MODE_GLOBAL = 7;
+
+ /** LTE, CDMA and EvDo */
+ int NETWORK_MODE_LTE_CDMA_EVDO = 8;
+
+ /** LTE, GSM and WCDMA */
+ int NETWORK_MODE_LTE_GSM_WCDMA = 9;
+
+ /** LTE, CDMA, EvDo, GSM, and WCDMA */
+ int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10;
+
+ /** LTE only mode. */
+ int NETWORK_MODE_LTE_ONLY = 11;
+
+ /** LTE and WCDMA */
+ int NETWORK_MODE_LTE_WCDMA = 12;
+
+ /** TD-SCDMA only */
+ int NETWORK_MODE_TDSCDMA_ONLY = 13;
+
+ /** TD-SCDMA and WCDMA */
+ int NETWORK_MODE_TDSCDMA_WCDMA = 14;
+
+ /** LTE and TD-SCDMA*/
+ int NETWORK_MODE_LTE_TDSCDMA = 15;
+
+ /** TD-SCDMA and GSM */
+ int NETWORK_MODE_TDSCDMA_GSM = 16;
+
+ /** TD-SCDMA, GSM and LTE */
+ int NETWORK_MODE_LTE_TDSCDMA_GSM = 17;
+
+ /** TD-SCDMA, GSM and WCDMA */
+ int NETWORK_MODE_TDSCDMA_GSM_WCDMA = 18;
+
+ /** LTE, TD-SCDMA and WCDMA */
+ int NETWORK_MODE_LTE_TDSCDMA_WCDMA = 19;
+
+ /** LTE, TD-SCDMA, GSM, and WCDMA */
+ int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20;
+
+ /** TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
+ int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21;
+
+ /** LTE, TDCSDMA, CDMA, EVDO, GSM and WCDMA */
+ int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22;
+
+ /** NR 5G only mode */
+ int NETWORK_MODE_NR_ONLY = 23;
+
+ /** NR 5G, LTE */
+ int NETWORK_MODE_NR_LTE = 24;
+
+ /** NR 5G, LTE, CDMA and EvDo */
+ int NETWORK_MODE_NR_LTE_CDMA_EVDO = 25;
+
+ /** NR 5G, LTE, GSM and WCDMA */
+ int NETWORK_MODE_NR_LTE_GSM_WCDMA = 26;
+
+ /** NR 5G, LTE, CDMA, EvDo, GSM and WCDMA */
+ int NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA = 27;
+
+ /** NR 5G, LTE and WCDMA */
+ int NETWORK_MODE_NR_LTE_WCDMA = 28;
+
+ /** NR 5G, LTE and TDSCDMA */
+ int NETWORK_MODE_NR_LTE_TDSCDMA = 29;
+
+ /** NR 5G, LTE, TD-SCDMA and GSM */
+ int NETWORK_MODE_NR_LTE_TDSCDMA_GSM = 30;
+
+ /** NR 5G, LTE, TD-SCDMA, WCDMA */
+ int NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA = 31;
+
+ /** NR 5G, LTE, TD-SCDMA, GSM and WCDMA */
+ int NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA = 32;
+
+ /** NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA */
+ int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33;
+
int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
"ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
@@ -192,31 +268,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;
@@ -424,6 +480,7 @@
int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
int RIL_REQUEST_EMERGENCY_DIAL = 205;
int RIL_REQUEST_GET_PHONE_CAPABILITY = 206;
+ int RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG = 207;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 6567ea7..603c4c2 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -194,6 +194,13 @@
*/
static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
+ /**
+ * Property to indicate if reboot is required when changing modems configurations
+ * Type: String(true, false) default is false; most devices don't need reboot
+ */
+ String PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE =
+ "persist.radio.reboot_on_modem_change";
+
/**
* Property to store default subscription.
*/
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 14a36c8..2016915 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -31,7 +31,7 @@
String callingPackage, in PendingIntent callbackIntent);
oneway void getDefaultDownloadableSubscriptionList(int cardId,
String callingPackage, in PendingIntent callbackIntent);
- String getEid(int cardId);
+ String getEid(int cardId, String callingPackage);
int getOtaStatus(int cardId);
oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 4f5bfa9..015efa6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -384,16 +384,22 @@
}
}
} catch (EncodeException ex) {
- // Encoding to the 7-bit alphabet failed. Let's see if we can
- // send it as a UCS-2 encoded message
- try {
- userData = encodeUCS2(message, header);
- encoding = ENCODING_16BIT;
- } catch(UnsupportedEncodingException uex) {
- Rlog.e(LOG_TAG,
- "Implausible UnsupportedEncodingException ",
- uex);
+ if (ex.getError() == EncodeException.ERROR_EXCEED_SIZE) {
+ Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex);
return null;
+ } else {
+ // Encoding to the 7-bit alphabet failed. Let's see if we can
+ // send it as a UCS-2 encoded message
+ try {
+ userData = encodeUCS2(message, header);
+ encoding = ENCODING_16BIT;
+ } catch (EncodeException ex1) {
+ Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex1);
+ return null;
+ } catch (UnsupportedEncodingException uex) {
+ Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
+ return null;
+ }
}
}
@@ -438,9 +444,10 @@
*
* @return encoded message as UCS2
* @throws UnsupportedEncodingException
+ * @throws EncodeException if String is too large to encode
*/
private static byte[] encodeUCS2(String message, byte[] header)
- throws UnsupportedEncodingException {
+ throws UnsupportedEncodingException, EncodeException {
byte[] userData, textPart;
textPart = message.getBytes("utf-16be");
@@ -455,6 +462,10 @@
else {
userData = textPart;
}
+ if (userData.length > 255) {
+ throw new EncodeException(
+ "Payload cannot exceed 255 bytes", EncodeException.ERROR_EXCEED_SIZE);
+ }
byte[] ret = new byte[userData.length+1];
ret[0] = (byte) (userData.length & 0xff );
System.arraycopy(userData, 0, ret, 1, userData.length);
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/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 299fbef..bdde096 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -22,18 +22,15 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
import android.net.LinkProperties.ProvisioningChange;
-import android.net.RouteInfo;
-import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.OsConstants;
import android.util.ArraySet;
+import com.android.internal.util.TestUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -849,18 +846,6 @@
assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
}
- private void assertParcelingIsLossless(LinkProperties source) {
- Parcel p = Parcel.obtain();
- source.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- final byte[] marshalled = p.marshall();
- p = Parcel.obtain();
- p.unmarshall(marshalled, 0, marshalled.length);
- p.setDataPosition(0);
- LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
- assertEquals(source, dest);
- }
-
@Test
public void testLinkPropertiesParcelable() throws Exception {
LinkProperties source = new LinkProperties();
@@ -882,12 +867,12 @@
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- assertParcelingIsLossless(source);
+ TestUtils.assertParcelingIsLossless(source, LinkProperties.CREATOR);
}
@Test
public void testParcelUninitialized() throws Exception {
LinkProperties empty = new LinkProperties();
- assertParcelingIsLossless(empty);
+ TestUtils.assertParcelingIsLossless(empty, LinkProperties.CREATOR);
}
}
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/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
new file mode 100644
index 0000000..1f2dd27
--- /dev/null
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.net.SocketKeepalive.InvalidPacketException;
+import android.net.TcpKeepalivePacketData.TcpSocketInfo;
+
+import com.android.internal.util.TestUtils;
+
+import libcore.net.InetAddressUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+@RunWith(JUnit4.class)
+public final class TcpKeepalivePacketDataTest {
+
+ @Before
+ public void setUp() {}
+
+ @Test
+ public void testV4TcpKeepalivePacket() {
+ final InetAddress srcAddr = InetAddressUtils.parseNumericAddress("192.168.0.1");
+ final InetAddress dstAddr = InetAddressUtils.parseNumericAddress("192.168.0.10");
+ final int srcPort = 1234;
+ final int dstPort = 4321;
+ final int seq = 0x11111111;
+ final int ack = 0x22222222;
+ final int wnd = 8000;
+ final int wndScale = 2;
+ TcpKeepalivePacketData resultData = null;
+ TcpSocketInfo testInfo = new TcpSocketInfo(
+ srcAddr, srcPort, dstAddr, dstPort, seq, ack, wnd, wndScale);
+ try {
+ resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
+ } catch (InvalidPacketException e) {
+ fail("InvalidPacketException: " + e);
+ }
+
+ assertEquals(testInfo.srcAddress, resultData.srcAddress);
+ assertEquals(testInfo.dstAddress, resultData.dstAddress);
+ assertEquals(testInfo.srcPort, resultData.srcPort);
+ assertEquals(testInfo.dstPort, resultData.dstPort);
+ assertEquals(testInfo.seq, resultData.tcpSeq);
+ assertEquals(testInfo.ack, resultData.tcpAck);
+ assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
+
+ TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
+
+ final byte[] packet = resultData.getPacket();
+ // IP version and TOS.
+ ByteBuffer buf = ByteBuffer.wrap(packet);
+ assertEquals(buf.getShort(), 0x4500);
+ // Source IP address.
+ byte[] ip = new byte[4];
+ buf = ByteBuffer.wrap(packet, 12, 4);
+ buf.get(ip);
+ assertArrayEquals(ip, srcAddr.getAddress());
+ // Destination IP address.
+ buf = ByteBuffer.wrap(packet, 16, 4);
+ buf.get(ip);
+ assertArrayEquals(ip, dstAddr.getAddress());
+
+ buf = ByteBuffer.wrap(packet, 20, 12);
+ // Source port.
+ assertEquals(buf.getShort(), srcPort);
+ // Destination port.
+ assertEquals(buf.getShort(), dstPort);
+ // Sequence number.
+ assertEquals(buf.getInt(), seq);
+ // Ack.
+ assertEquals(buf.getInt(), ack);
+ // Window size.
+ buf = ByteBuffer.wrap(packet, 34, 2);
+ assertEquals(buf.getShort(), wnd >> wndScale);
+ }
+
+ //TODO: add ipv6 test when ipv6 supported
+
+ @Test
+ public void testParcel() throws Exception {
+ final InetAddress srcAddr = InetAddresses.parseNumericAddress("192.168.0.1");
+ final InetAddress dstAddr = InetAddresses.parseNumericAddress("192.168.0.10");
+ final int srcPort = 1234;
+ final int dstPort = 4321;
+ final int sequence = 0x11111111;
+ final int ack = 0x22222222;
+ final int wnd = 48_000;
+ final int wndScale = 2;
+ TcpKeepalivePacketData testData = null;
+ TcpKeepalivePacketDataParcelable resultData = null;
+ TcpSocketInfo testInfo = new TcpSocketInfo(
+ srcAddr, srcPort, dstAddr, dstPort, sequence, ack, wnd, wndScale);
+ testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
+ resultData = testData.toStableParcelable();
+ assertArrayEquals(resultData.srcAddress, srcAddr.getAddress());
+ assertArrayEquals(resultData.dstAddress, dstAddr.getAddress());
+ assertEquals(resultData.srcPort, srcPort);
+ assertEquals(resultData.dstPort, dstPort);
+ assertEquals(resultData.seq, sequence);
+ assertEquals(resultData.ack, ack);
+ }
+}
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/internal/util/TestUtils.java b/tests/net/java/com/android/internal/util/TestUtils.java
index 6db01d3..7e5a1d3 100644
--- a/tests/net/java/com/android/internal/util/TestUtils.java
+++ b/tests/net/java/com/android/internal/util/TestUtils.java
@@ -16,12 +16,15 @@
package com.android.internal.util;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
public final class TestUtils {
private TestUtils() { }
@@ -50,4 +53,18 @@
fail(handler.toString() + " did not become idle after " + timeoutMs + " ms");
}
}
+
+ // TODO : fetch the creator through reflection or something instead of passing it
+ public static <T extends Parcelable, C extends Parcelable.Creator<T>>
+ void assertParcelingIsLossless(T source, C creator) {
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalled = p.marshall();
+ p = Parcel.obtain();
+ p.unmarshall(marshalled, 0, marshalled.length);
+ p.setDataPosition(0);
+ T dest = creator.createFromParcel(p);
+ assertEquals(source, dest);
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b5d5f61..1548a76 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;
@@ -190,6 +194,7 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -480,8 +485,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(
@@ -496,17 +501,17 @@
public void unwanted() { mDisconnected.open(); }
@Override
- public void startPacketKeepalive(Message msg) {
+ public void startSocketKeepalive(Message msg) {
int slot = msg.arg1;
if (mExpectedKeepaliveSlot != null) {
assertEquals((int) mExpectedKeepaliveSlot, slot);
}
- onPacketKeepaliveEvent(slot, mStartKeepaliveError);
+ onSocketKeepaliveEvent(slot, mStartKeepaliveError);
}
@Override
- public void stopPacketKeepalive(Message msg) {
- onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
+ public void stopSocketKeepalive(Message msg) {
+ onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
}
@Override
@@ -521,7 +526,8 @@
}
};
- assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+ assertEquals(
+ mNetworkAgent.netId, fromStableParcelable(nmNetworkCaptor.getValue()).netId);
mNmCallbacks = nmCbCaptor.getValue();
try {
@@ -901,6 +907,7 @@
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mConnected = true;
mConfig = new VpnConfig();
+ mConfig.isMetered = false;
}
@Override
@@ -1007,6 +1014,11 @@
}
@Override
+ protected ProxyTracker makeProxyTracker() {
+ return mock(ProxyTracker.class);
+ }
+
+ @Override
protected int reserveNetId() {
while (true) {
final int netId = super.reserveNetId();
@@ -1028,6 +1040,11 @@
}
}
+ @Override
+ protected boolean queryUserAccess(int uid, int netId) {
+ return true;
+ }
+
public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
}
@@ -3775,10 +3792,17 @@
@Test
public void testNattSocketKeepalives() throws Exception {
+ final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
+ doTestNattSocketKeepalivesWithExecutor(executorSingleThread);
+ executorSingleThread.shutdown();
+
+ final Executor executorInline = (Runnable r) -> r.run();
+ doTestNattSocketKeepalivesWithExecutor(executorInline);
+ }
+
+ private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
// TODO: 1. Move this outside of ConnectivityServiceTest.
- // 2. Add helper function to test against newSingleThreadExecutor as well as inline
- // executor.
- // 3. Make test to verify that Nat-T keepalive socket is created by IpSecService.
+ // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
final int srcPort = 12345;
final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
@@ -3792,8 +3816,6 @@
final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort);
- final Executor executor = Executors.newSingleThreadExecutor();
-
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("wlan12");
lp.addLinkAddress(new LinkAddress(myIPv6, 64));
@@ -3910,6 +3932,11 @@
ka2.stop();
callback2.expectStopped();
+
+ testSocket.close();
+ testSocket2.close();
+
+ mWiFiNetworkAgent.disconnect();
}
@Test
@@ -5132,4 +5159,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/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 125fe725..273b8fc 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
+
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
@@ -34,26 +35,24 @@
import android.content.res.Resources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import org.junit.runner.RunWith;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkNotificationManagerTest {
@@ -194,4 +193,54 @@
mManager.clearNotification(id);
verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
}
+
+ @Test
+ public void testSameLevelNotifications() {
+ final int id = 101;
+ final String tag = NetworkNotificationManager.tagFor(id);
+
+ mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+
+ mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
+ }
+
+ @Test
+ public void testClearNotificationByType() {
+ final int id = 101;
+ final String tag = NetworkNotificationManager.tagFor(id);
+
+ // clearNotification(int id, NotificationType notifyType) will check if given type is equal
+ // to previous type or not. If they are equal then clear the notification; if they are not
+ // equal then return.
+
+ mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+
+ // Previous notification is LOGGED_IN and given type is LOGGED_IN too. The notification
+ // should be cleared.
+ mManager.clearNotification(id, LOGGED_IN);
+ verify(mNotificationManager, times(1))
+ .cancelAsUser(eq(tag), eq(LOGGED_IN.eventId), any());
+
+ mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(2))
+ .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+
+ // LOST_INTERNET notification popup after LOGGED_IN notification.
+ mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
+ verify(mNotificationManager, times(1))
+ .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
+
+ // Previous notification is LOST_INTERNET and given type is LOGGED_IN. The notification
+ // shouldn't be cleared.
+ mManager.clearNotification(id, LOGGED_IN);
+ // LOST_INTERNET shouldn't be cleared.
+ verify(mNotificationManager, never())
+ .cancelAsUser(eq(tag), eq(LOST_INTERNET.eventId), any());
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0b74d87..46de3d0 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -168,6 +168,8 @@
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
+ when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
doNothing().when(mNetService).registerObserver(any());
}
@@ -246,17 +248,17 @@
assertFalse(vpn.getLockdown());
// Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
assertTrue(vpn.getAlwaysOn());
assertFalse(vpn.getLockdown());
// Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
assertTrue(vpn.getAlwaysOn());
assertTrue(vpn.getLockdown());
// Remove always-on configuration.
- assertTrue(vpn.setAlwaysOnPackage(null, false));
+ assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
assertFalse(vpn.getAlwaysOn());
assertFalse(vpn.getLockdown());
}
@@ -270,11 +272,11 @@
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -283,7 +285,7 @@
assertUnblocked(vpn, user.start + PKG_UIDS[1]);
// Switch to another app.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -297,6 +299,87 @@
}
@Test
+ public void testLockdownWhitelist() throws Exception {
+ final Vpn vpn = createVpn(primaryUser.id);
+ final UidRange user = UidRange.createForUser(primaryUser.id);
+
+ // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+ new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ }));
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+
+ // Change whitelisted app to PKGS[3].
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ }));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
+ new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+ }));
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
+
+ // Change the VPN app.
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+ new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+ }));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+ new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+ }));
+ assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+
+ // Remove the whitelist.
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
+ new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+ }));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
+ }));
+ assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
+ user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0]);
+
+ // Add the whitelist.
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
+ }));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+ new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ }));
+ assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
+
+ // Try whitelisting a package with a comma, should be rejected.
+ assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
+
+ // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
+ // Whitelisted package should change from PGKS[1] to PKGS[2].
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
+ Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+ new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ }));
+ verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
+ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
+ new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ }));
+ }
+
+ @Test
public void testLockdownAddingAProfile() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
@@ -310,7 +393,7 @@
final UidRange profile = UidRange.createForUser(tempProfile.id);
// Set lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+ assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -436,7 +519,7 @@
.cancelAsUser(anyString(), anyInt(), eq(userHandle));
// Start showing a notification for disconnected once always-on.
- vpn.setAlwaysOnPackage(PKGS[0], false);
+ vpn.setAlwaysOnPackage(PKGS[0], false, null);
order.verify(mNotificationManager)
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
@@ -450,7 +533,7 @@
.notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
// Notification should be cleared after unsetting always-on package.
- vpn.setAlwaysOnPackage(null, false);
+ vpn.setAlwaysOnPackage(null, false, null);
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
}
@@ -463,23 +546,28 @@
final Network wifi = new Network(2);
final Map<Network, NetworkCapabilities> networks = new HashMap<>();
- networks.put(mobile, new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(wifi, new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkUpstreamBandwidthKbps(20));
+ networks.put(
+ mobile,
+ new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkDownstreamBandwidthKbps(10));
+ networks.put(
+ wifi,
+ new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkUpstreamBandwidthKbps(20));
setMockedNetworks(networks);
final NetworkCapabilities caps = new NetworkCapabilities();
- Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
+ Vpn.updateCapabilities(
+ mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
assertFalse(caps.hasTransport(TRANSPORT_WIFI));
@@ -489,17 +577,33 @@
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
+ Vpn.updateCapabilities(
+ mConnectivityManager,
+ new Network[] {mobile},
+ caps,
+ false /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
assertFalse(caps.hasTransport(TRANSPORT_WIFI));
assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
+ Vpn.updateCapabilities(
+ mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+ Vpn.updateCapabilities(
+ mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(caps.hasTransport(TRANSPORT_WIFI));
@@ -509,7 +613,11 @@
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
+ Vpn.updateCapabilities(
+ mConnectivityManager,
+ new Network[] {mobile, wifi},
+ caps,
+ false /* isAlwaysMetered */);
assertTrue(caps.hasTransport(TRANSPORT_VPN));
assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
assertTrue(caps.hasTransport(TRANSPORT_WIFI));
@@ -583,7 +691,9 @@
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/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 0f72229..ec286759 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -16,8 +16,16 @@
package com.android.server.connectivity.tethering;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -27,12 +35,22 @@
import android.content.Context;
import android.content.res.Resources;
import android.net.util.SharedLog;
+import android.os.Bundle;
+import android.os.Message;
import android.os.PersistableBundle;
+import android.os.ResultReceiver;
+import android.os.test.TestLooper;
+import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.CarrierConfigManager;
+import android.test.mock.MockContentResolver;
import com.android.internal.R;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.MockableSystemProperties;
import org.junit.After;
@@ -42,6 +60,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public final class EntitlementManagerTest {
@@ -51,7 +73,6 @@
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private Context mContext;
- @Mock private ContentResolver mContent;
@Mock private MockableSystemProperties mSystemProperties;
@Mock private Resources mResources;
@Mock private SharedLog mLog;
@@ -59,15 +80,49 @@
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle();
+ private final TestLooper mLooper = new TestLooper();
+ private Context mMockContext;
+ private MockContentResolver mContentResolver;
- private EntitlementManager mEnMgr;
+ private TestStateMachine mSM;
+ private WrappedEntitlementManager mEnMgr;
+
+ private class MockContext extends BroadcastInterceptingContext {
+ MockContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResources;
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
+ }
+
+ public class WrappedEntitlementManager extends EntitlementManager {
+ public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ public boolean everRunUiEntitlement = false;
+
+ public WrappedEntitlementManager(Context ctx, StateMachine target,
+ SharedLog log, MockableSystemProperties systemProperties) {
+ super(ctx, target, log, systemProperties);
+ }
+
+ @Override
+ protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
+ everRunUiEntitlement = true;
+ receiver.send(fakeEntitlementResult, null);
+ }
+ }
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mContext.getResources()).thenReturn(mResources);
- when(mContext.getContentResolver()).thenReturn(mContent);
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
@@ -80,12 +135,21 @@
.thenReturn(new int[0]);
when(mLog.forSubComponent(anyString())).thenReturn(mLog);
- mEnMgr = new EntitlementManager(mContext, mLog, mSystemProperties);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mContentResolver = new MockContentResolver();
+ mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ mMockContext = new MockContext(mContext);
+ mSM = new TestStateMachine();
+ mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties);
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
}
@After
- public void tearDown() throws Exception {}
+ public void tearDown() throws Exception {
+ if (mSM != null) {
+ mSM.quit();
+ mSM = null;
+ }
+ }
private void setupForRequiredProvisioning() {
// Produce some acceptable looking provision app setting if requested.
@@ -104,7 +168,7 @@
@Test
public void canRequireProvisioning() {
setupForRequiredProvisioning();
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -113,7 +177,7 @@
setupForRequiredProvisioning();
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
// Therefore provisioning still be required.
assertTrue(mEnMgr.isTetherProvisioningRequired());
@@ -123,7 +187,7 @@
public void toleratesCarrierConfigMissing() {
setupForRequiredProvisioning();
when(mCarrierConfigManager.getConfig()).thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
// We still have a provisioning app configured, so still require provisioning.
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -133,12 +197,143 @@
setupForRequiredProvisioning();
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
assertFalse(mEnMgr.isTetherProvisioningRequired());
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(new String[] {"malformedApp"});
- mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
assertFalse(mEnMgr.isTetherProvisioningRequired());
}
+ @Test
+ public void testGetLastEntitlementCacheValue() throws Exception {
+ final CountDownLatch mCallbacklatch = new CountDownLatch(1);
+ // 1. Entitlement check is not required.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.everRunUiEntitlement = false;
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_NO_ERROR, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, true);
+ callbackTimeoutHelper(mCallbacklatch);
+ assertFalse(mEnMgr.everRunUiEntitlement);
+
+ setupForRequiredProvisioning();
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ // 2. No cache value and don't need to run entitlement check.
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, false);
+ callbackTimeoutHelper(mCallbacklatch);
+ assertFalse(mEnMgr.everRunUiEntitlement);
+ // 3. No cache value and ui entitlement check is needed.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_PROVISION_FAILED, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, true);
+ mLooper.dispatchAll();
+ callbackTimeoutHelper(mCallbacklatch);
+ assertTrue(mEnMgr.everRunUiEntitlement);
+ // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_PROVISION_FAILED, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, false);
+ callbackTimeoutHelper(mCallbacklatch);
+ assertFalse(mEnMgr.everRunUiEntitlement);
+ // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_NO_ERROR, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, true);
+ mLooper.dispatchAll();
+ callbackTimeoutHelper(mCallbacklatch);
+ assertTrue(mEnMgr.everRunUiEntitlement);
+ // 6. Cache value is TETHER_ERROR_NO_ERROR.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_NO_ERROR, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_WIFI, receiver, true);
+ callbackTimeoutHelper(mCallbacklatch);
+ assertFalse(mEnMgr.everRunUiEntitlement);
+ // 7. Test get value for other downstream type.
+ mEnMgr.everRunUiEntitlement = false;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.getLatestTetheringEntitlementValue(TETHERING_USB, receiver, false);
+ callbackTimeoutHelper(mCallbacklatch);
+ assertFalse(mEnMgr.everRunUiEntitlement);
+ }
+
+ void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
+ if (!latch.await(1, TimeUnit.SECONDS)) {
+ fail("Timout, fail to recieve callback");
+ }
+ }
+ public class TestStateMachine extends StateMachine {
+ public final ArrayList<Message> messages = new ArrayList<>();
+ private final State mLoggingState =
+ new EntitlementManagerTest.TestStateMachine.LoggingState();
+
+ class LoggingState extends State {
+ @Override public void enter() {
+ messages.clear();
+ }
+
+ @Override public void exit() {
+ messages.clear();
+ }
+
+ @Override public boolean processMessage(Message msg) {
+ messages.add(msg);
+ return false;
+ }
+ }
+
+ public TestStateMachine() {
+ super("EntitlementManagerTest.TestStateMachine", mLooper.getLooper());
+ addState(mLoggingState);
+ setInitialState(mLoggingState);
+ super.start();
+ }
+ }
}
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)