summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp26
-rw-r--r--Android.mk18
-rw-r--r--api/current.txt15
-rw-r--r--api/system-current.txt29
-rw-r--r--api/system-lint-baseline.txt10
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/annotation/UnsupportedAppUsage.java9
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl6
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.aidl (renamed from core/java/android/app/timedetector/TimeSignal.aidl)2
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java137
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java6
-rw-r--r--core/java/android/app/timedetector/TimeSignal.java109
-rw-r--r--core/java/android/bluetooth/le/ScanRecord.java2
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/net/ConnectivityManager.java8
-rw-r--r--core/java/android/net/MacAddress.java2
-rw-r--r--core/java/android/net/NetworkCapabilities.java44
-rw-r--r--core/java/android/net/NetworkMisc.java6
-rw-r--r--core/java/android/os/ConfigUpdate.java15
-rw-r--r--core/java/android/service/euicc/EuiccService.java13
-rw-r--r--core/java/com/android/internal/compat/ChangeReporter.java79
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl8
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/res/AndroidManifest.xml20
-rw-r--r--core/res/res/values/config.xml10
-rw-r--r--core/res/res/values/strings.xml19
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/PlatformCompatFramework/Android.bp14
-rw-r--r--core/tests/PlatformCompatFramework/AndroidManifest.xml11
-rw-r--r--core/tests/PlatformCompatFramework/OWNERS7
-rw-r--r--core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java115
-rw-r--r--core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java75
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--media/java/android/media/AudioSystem.java47
-rw-r--r--media/java/android/media/JetPlayer.java12
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java4
-rw-r--r--media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl4
-rw-r--r--media/java/android/media/midi/MidiDeviceInfo.aidl2
-rw-r--r--media/jni/Android.bp9
-rw-r--r--media/jni/JetPlayer.cpp471
-rw-r--r--media/jni/JetPlayer.h126
-rw-r--r--media/jni/android_media_JetPlayer.cpp (renamed from core/jni/android_media_JetPlayer.cpp)2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp6
-rw-r--r--media/native/midi/Android.bp7
-rw-r--r--media/native/midi/MidiDeviceInfo.cpp138
-rw-r--r--media/native/midi/MidiDeviceInfo.h81
-rw-r--r--media/native/midi/amidi.cpp2
-rw-r--r--native/android/Android.bp28
-rw-r--r--native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl93
-rw-r--r--packages/CarrierDefaultApp/OWNERS3
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java5
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java16
-rw-r--r--packages/SettingsLib/res/values/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java9
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/Tethering/Android.bp72
-rw-r--r--packages/Tethering/AndroidManifest.xml29
-rw-r--r--packages/Tethering/AndroidManifestBase.xml29
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp40
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl20
-rw-r--r--packages/Tethering/proguard.flags1
-rw-r--r--packages/Tethering/res/values/config.xml7
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java (renamed from services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java)25
-rw-r--r--packages/Tethering/tests/unit/Android.bp47
-rw-r--r--packages/Tethering/tests/unit/AndroidManifest.xml26
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java (renamed from tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java)36
-rw-r--r--proto/src/system_messages.proto2
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java83
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java34
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java16
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompatNative.java50
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java21
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java74
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java43
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java6
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java4
-rw-r--r--services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java39
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/net/Android.bp9
-rw-r--r--services/net/java/android/net/ip/IpServer.java5
-rw-r--r--services/net/java/android/net/netlink/InetDiagMessage.java35
-rw-r--r--services/net/java/android/net/netlink/StructInetDiagReqV2.java63
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java88
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java31
-rw-r--r--telecomm/java/android/telecom/Call.java4
-rw-r--r--telecomm/java/android/telecom/Connection.java334
-rw-r--r--telephony/OWNERS3
-rw-r--r--telephony/java/android/telephony/CellBroadcastService.java112
-rw-r--r--telephony/java/android/telephony/CellIdentity.java52
-rw-r--r--telephony/java/android/telephony/DisconnectCause.java17
-rw-r--r--telephony/java/android/telephony/ICellBroadcastService.aidl32
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java34
-rw-r--r--telephony/java/android/telephony/ims/ImsReasonInfo.java13
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl12
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java11
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java26
-rw-r--r--telephony/java/com/android/internal/telephony/uicc/IccUtils.java30
-rw-r--r--tests/BootImageProfileTest/AndroidTest.xml4
-rw-r--r--tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java25
-rw-r--r--tests/net/Android.bp8
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java2
-rw-r--r--tests/net/java/android/net/ip/IpServerTest.java27
-rw-r--r--tests/net/java/android/net/netlink/InetDiagSocketTest.java102
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java166
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java202
-rw-r--r--tools/stats_log_api_gen/Android.bp2
110 files changed, 3434 insertions, 647 deletions
diff --git a/Android.bp b/Android.bp
index 77f024bab01e..a913324aa9ca 100644
--- a/Android.bp
+++ b/Android.bp
@@ -194,6 +194,9 @@ filegroup {
":PacProcessor-aidl-sources",
":ProxyHandler-aidl-sources",
+ // AIDL from frameworks/base/native/
+ ":platform-compat-native-aidl",
+
// AIDL sources from external directories
":dumpstate_aidl",
":framework_native_aidl",
@@ -508,6 +511,12 @@ filegroup {
],
}
+filegroup {
+ name: "framework-tethering-shared-srcs",
+ srcs: [
+ "core/java/android/util/LocalLog.java",
+ ],
+}
// Build ext.jar
// ============================================================
java_library {
@@ -1019,6 +1028,7 @@ droidstubs {
"core/res/AndroidManifest.xml",
],
args: metalava_framework_docs_args,
+ write_sdk_values: true,
}
droidstubs {
@@ -1028,6 +1038,7 @@ droidstubs {
"core/res/AndroidManifest.xml",
],
args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi ",
+ write_sdk_values: true,
}
droiddoc {
@@ -1051,7 +1062,6 @@ droiddoc {
],
proofread_file: "offline-sdk-docs-proofrerad.txt",
args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
- write_sdk_values: true,
static_doc_index_redirect: "docs/docs-preview-index.html",
}
@@ -1069,7 +1079,6 @@ droiddoc {
],
proofread_file: "offline-sdk-referenceonly-docs-proofrerad.txt",
args: framework_docs_only_args + " -offlinemode -title \"Android SDK\" -referenceonly",
- write_sdk_values: true,
static_doc_index_redirect: "docs/docs-documentation-redirect.html",
static_doc_properties: "docs/source.properties",
}
@@ -1089,7 +1098,6 @@ droiddoc {
proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
args: framework_docs_only_args + " -hide 101 -hide 104 -hide 108" +
" -offlinemode -title \"Android System SDK\" -referenceonly",
- write_sdk_values: true,
static_doc_index_redirect: "docs/docs-documentation-redirect.html",
static_doc_properties: "docs/source.properties",
}
@@ -1531,3 +1539,15 @@ genrule {
targets: ["droidcore"],
},
}
+
+// Avoid including Parcelable classes as we don't want to have two copies of
+// Parcelable cross the process.
+filegroup {
+ name: "framework-cellbroadcast-shared-srcs",
+ srcs: [
+ "core/java/android/util/LocalLog.java",
+ "core/java/android/util/Slog.java",
+ "core/java/com/android/internal/util/State.java",
+ "core/java/com/android/internal/util/StateMachine.java",
+ ],
+}
diff --git a/Android.mk b/Android.mk
index 9bda2dc6d69a..815a169f3880 100644
--- a/Android.mk
+++ b/Android.mk
@@ -54,6 +54,24 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
.PHONY: docs offline-sdk-docs
docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp
+SDK_METADATA_DIR :=$= $(call intermediates-dir-for,PACKAGING,framework-doc-stubs-metadata,,COMMON)
+SDK_METADATA_FILES :=$= $(addprefix $(SDK_METADATA_DIR)/,\
+ activity_actions.txt \
+ broadcast_actions.txt \
+ categories.txt \
+ features.txt \
+ service_actions.txt \
+ widgets.txt)
+SDK_METADATA :=$= $(firstword $(SDK_METADATA_FILES))
+$(SDK_METADATA): .KATI_IMPLICIT_OUTPUTS := $(filter-out $(SDK_METADATA),$(SDK_METADATA_FILES))
+$(SDK_METADATA): $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/framework-doc-stubs-metadata.zip
+ rm -rf $(SDK_METADATA_DIR)
+ mkdir -p $(SDK_METADATA_DIR)
+ unzip -qo $< -d $(SDK_METADATA_DIR)
+
+.PHONY: framework-doc-stubs
+framework-doc-stubs: $(SDK_METADATA)
+
# Run this for checkbuild
checkbuild: doc-comment-check-docs
diff --git a/api/current.txt b/api/current.txt
index c396d74116b6..0c60fc16c5c4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28766,7 +28766,9 @@ package android.net {
method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
method @NonNull public static android.net.MacAddress fromString(@NonNull String);
method public int getAddressType();
+ method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
method public boolean isLocallyAssigned();
+ method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
method @NonNull public byte[] toByteArray();
method @NonNull public String toOuiString();
method public void writeToParcel(android.os.Parcel, int);
@@ -43284,8 +43286,10 @@ package android.telecom {
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
+ method public final int getVideoState();
method public void handleRttUpgradeResponse(@Nullable android.telecom.Connection.RttTextStream);
method public final boolean isRingbackRequested();
+ method public final void notifyConferenceMergeFailed();
method public void onAbort();
method public void onAnswer(int);
method public void onAnswer();
@@ -43364,8 +43368,15 @@ package android.telecom {
field public static final int CAPABILITY_SUPPORT_DEFLECT = 33554432; // 0x2000000
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+ field public static final String EVENT_CALL_HOLD_FAILED = "android.telecom.event.CALL_HOLD_FAILED";
field public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
field public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final String EVENT_CALL_REMOTELY_HELD = "android.telecom.event.CALL_REMOTELY_HELD";
+ field public static final String EVENT_CALL_REMOTELY_UNHELD = "android.telecom.event.CALL_REMOTELY_UNHELD";
+ field public static final String EVENT_MERGE_COMPLETE = "android.telecom.event.MERGE_COMPLETE";
+ field public static final String EVENT_MERGE_START = "android.telecom.event.MERGE_START";
+ field public static final String EVENT_ON_HOLD_TONE_END = "android.telecom.event.ON_HOLD_TONE_END";
+ field public static final String EVENT_ON_HOLD_TONE_START = "android.telecom.event.ON_HOLD_TONE_START";
field public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED = "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
@@ -43375,9 +43386,12 @@ package android.telecom {
field public static final String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
field public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+ field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
+ field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
+ field public static final int PROPERTY_WIFI = 8; // 0x8
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -45041,6 +45055,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
method public boolean setLine1NumberForDisplay(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index b674e928bd6f..b81dec044ab7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24,6 +24,7 @@ package android {
field public static final String BACKUP = "android.permission.BACKUP";
field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
+ field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE";
@@ -5156,6 +5157,7 @@ package android.os {
field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
field public static final String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
field public static final String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
+ field public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
field public static final String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
field public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
field public static final String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
@@ -6917,7 +6919,26 @@ package android.telecom {
public abstract class Connection extends android.telecom.Conferenceable {
method @Deprecated public final android.telecom.AudioState getAudioState();
+ method public final int getCallRadioTech();
+ method public final long getConnectElapsedTimeMillis();
+ method public final long getConnectTimeMillis();
+ method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+ method @Nullable public final String getTelecomCallId();
method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
+ method public final void resetConnectionTime();
+ method public void setCallDirection(int);
+ method public final void setCallRadioTech(int);
+ method public final void setConnectTimeMillis(long);
+ method public final void setConnectionStartElapsedRealTime(long);
+ method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+ method public void setTelecomCallId(@NonNull String);
+ field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
+ field public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 262144; // 0x40000
+ field public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";
+ field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1; // 0x1
+ field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 64; // 0x40
+ field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
public abstract class InCallService extends android.app.Service {
@@ -7214,6 +7235,14 @@ package android.telephony {
method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
}
+ public abstract class CellBroadcastService extends android.app.Service {
+ ctor public CellBroadcastService();
+ method @CallSuper public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onCdmaCellBroadcastSms(int, byte[]);
+ method public abstract void onGsmCellBroadcastSms(int, byte[]);
+ field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
+ }
+
public final class DataFailCause {
field public static final int ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219; // 0x8ab
field public static final int ACCESS_BLOCK = 2087; // 0x827
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 954a2ea0e347..fffec3e739ae 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -51,6 +51,14 @@ MissingNullability: android.service.notification.NotificationAssistantService#at
MissingNullability: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallFurther(boolean):
+MissingNullability: android.telephony.CellBroadcastService#onBind(android.content.Intent):
+ Missing nullability on method `onBind` return
+MissingNullability: android.telephony.CellBroadcastService#onBind(android.content.Intent) parameter #0:
+ Missing nullability on parameter `intent` in method `onBind`
+MissingNullability: android.telephony.CellBroadcastService#onCdmaCellBroadcastSms(int, byte[]) parameter #1:
+ Missing nullability on parameter `message` in method `onCdmaCellBroadcastSms`
+MissingNullability: android.telephony.CellBroadcastService#onGsmCellBroadcastSms(int, byte[]) parameter #1:
+ Missing nullability on parameter `message` in method `onGsmCellBroadcastSms`
MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
MissingNullability: android.telephony.SmsCbCmasInfo#toString():
@@ -317,6 +325,8 @@ ServiceName: android.Manifest.permission#BIND_ATTENTION_SERVICE:
ServiceName: android.Manifest.permission#BIND_AUGMENTED_AUTOFILL_SERVICE:
+ServiceName: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
+ Inconsistent service value; expected `BIND_CELL_BROADCAST`, was `android.permission.BIND_CELL_BROADCAST_SERVICE`
ServiceName: android.Manifest.permission#BIND_CONTENT_CAPTURE_SERVICE:
ServiceName: android.Manifest.permission#BIND_CONTENT_SUGGESTIONS_SERVICE:
diff --git a/api/test-current.txt b/api/test-current.txt
index 1cf1cd3b4196..620e93113a5d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5,6 +5,7 @@ package android {
field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
+ field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
index a454df5d68f4..204d71d93cd8 100644
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -83,8 +83,9 @@ public @interface UnsupportedAppUsage {
* <p>Possible values are:
* <ul>
* <li>
- * {@link android.os.Build.VERSION_CODES#O} or {@link android.os.Build.VERSION_CODES#P},
- * to limit access to apps targeting these SDKs (or earlier).
+ * An API level like {@link android.os.Build.VERSION_CODES#O} - in which case the API is
+ * available up to and including the specified release. Or, in other words, the API is
+ * blacklisted (unavailable) from the next API level from the one specified.
* </li>
* <li>
* absent (default value) - All apps can access this API, but doing so may result in
@@ -94,10 +95,6 @@ public @interface UnsupportedAppUsage {
*
* </ul>
*
- * Note, if this is set to {@link android.os.Build.VERSION_CODES#O}, apps targeting O
- * maintenance releases will also be allowed to use the API, and similarly for any future
- * maintenance releases of P.
- *
* @return The maximum value for an apps targetSdkVersion in order to access this API.
*/
int maxTargetSdk() default Integer.MAX_VALUE;
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index f624446a2027..ddc4932d6fec 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,10 +16,10 @@
package android.app.timedetector;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
/**
- * System private API to comunicate with time detector service.
+ * System private API to communicate with time detector service.
*
* <p>Used by parts of the Android system with signals associated with the device's time to provide
* information to the Time Detector Service.
@@ -32,5 +32,5 @@ import android.app.timedetector.TimeSignal;
* {@hide}
*/
interface ITimeDetectorService {
- void suggestTime(in TimeSignal timeSignal);
+ void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/TimeSignal.aidl b/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
index d2ec357555bc..f5e240549a9a 100644
--- a/core/java/android/app/timedetector/TimeSignal.aidl
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
@@ -16,4 +16,4 @@
package android.app.timedetector;
-parcelable TimeSignal; \ No newline at end of file
+parcelable PhoneTimeSuggestion;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
new file mode 100644
index 000000000000..475a4aafd929
--- /dev/null
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -0,0 +1,137 @@
+/*
+ * 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.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a telephony source. The value consists of the number of milliseconds elapsed
+ * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
+ * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
+ * must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class PhoneTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
+ new Parcelable.Creator<PhoneTimeSuggestion>() {
+ public PhoneTimeSuggestion createFromParcel(Parcel in) {
+ return PhoneTimeSuggestion.createFromParcel(in);
+ }
+
+ public PhoneTimeSuggestion[] newArray(int size) {
+ return new PhoneTimeSuggestion[size];
+ }
+ };
+
+ private final int mPhoneId;
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
+
+ public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
+ mPhoneId = phoneId;
+ mUtcTime = Objects.requireNonNull(utcTime);
+ }
+
+ private static PhoneTimeSuggestion createFromParcel(Parcel in) {
+ int phoneId = in.readInt();
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPhoneId);
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ public int getPhoneId() {
+ return mPhoneId;
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
+ return mPhoneId == that.mPhoneId
+ && Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPhoneId, mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneTimeSuggestion{"
+ + "mPhoneId='" + mPhoneId + '\''
+ + ", mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 052050df8c9a..334e9582a145 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -45,12 +45,12 @@ public final class TimeDetector {
* signals are available such as those that come from more reliable sources or were
* determined more recently.
*/
- public void suggestTime(@NonNull TimeSignal timeSignal) {
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) {
- Log.d(TAG, "suggestTime called: " + timeSignal);
+ Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
}
try {
- mITimeDetectorService.suggestTime(timeSignal);
+ mITimeDetectorService.suggestPhoneTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/timedetector/TimeSignal.java b/core/java/android/app/timedetector/TimeSignal.java
deleted file mode 100644
index b49426000d88..000000000000
--- a/core/java/android/app/timedetector/TimeSignal.java
+++ /dev/null
@@ -1,109 +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.app.timedetector;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.TimestampedValue;
-
-import java.util.Objects;
-
-/**
- * A time signal from a named source. The value consists of the number of milliseconds elapsed since
- * 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number was
- * established. The elapsed realtime clock is considered accurate but volatile, so time signals
- * must not be persisted across device resets.
- *
- * @hide
- */
-public final class TimeSignal implements Parcelable {
-
- public static final @android.annotation.NonNull Parcelable.Creator<TimeSignal> CREATOR =
- new Parcelable.Creator<TimeSignal>() {
- public TimeSignal createFromParcel(Parcel in) {
- return TimeSignal.createFromParcel(in);
- }
-
- public TimeSignal[] newArray(int size) {
- return new TimeSignal[size];
- }
- };
-
- public static final String SOURCE_ID_NITZ = "nitz";
-
- private final String mSourceId;
- private final TimestampedValue<Long> mUtcTime;
-
- public TimeSignal(String sourceId, TimestampedValue<Long> utcTime) {
- mSourceId = Objects.requireNonNull(sourceId);
- mUtcTime = Objects.requireNonNull(utcTime);
- }
-
- private static TimeSignal createFromParcel(Parcel in) {
- String sourceId = in.readString();
- TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
- return new TimeSignal(sourceId, utcTime);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mSourceId);
- dest.writeParcelable(mUtcTime, 0);
- }
-
- @NonNull
- public String getSourceId() {
- return mSourceId;
- }
-
- @NonNull
- public TimestampedValue<Long> getUtcTime() {
- return mUtcTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TimeSignal that = (TimeSignal) o;
- return Objects.equals(mSourceId, that.mSourceId)
- && Objects.equals(mUtcTime, that.mUtcTime);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mSourceId, mUtcTime);
- }
-
- @Override
- public String toString() {
- return "TimeSignal{"
- + "mSourceId='" + mSourceId + '\''
- + ", mUtcTime=" + mUtcTime
- + '}';
- }
-}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 30868bfeac66..97e3f5221c72 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -154,7 +154,7 @@ public final class ScanRecord {
}
/**
- * Returns the local name of the BLE device. The is a UTF-8 encoded string.
+ * Returns the local name of the BLE device. This is a UTF-8 encoded string.
*/
@Nullable
public String getDeviceName() {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a6b95a95dcd8..51bb85a7fe8e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -74,6 +74,7 @@ import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import android.view.textclassifier.TextClassificationManager;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.compat.IPlatformCompatNative;
import java.io.File;
import java.io.FileInputStream;
@@ -3231,6 +3232,7 @@ public abstract class Context {
//@hide ROLE_CONTROLLER_SERVICE,
CAMERA_SERVICE,
//@hide: PLATFORM_COMPAT_SERVICE,
+ //@hide: PLATFORM_COMPAT_NATIVE_SERVICE,
PRINT_SERVICE,
CONSUMER_IR_SERVICE,
//@hide: TRUST_SERVICE,
@@ -4596,6 +4598,14 @@ public abstract class Context {
public static final String PLATFORM_COMPAT_SERVICE = "platform_compat";
/**
+ * Use with {@link android.os.ServiceManager.getService()} to retrieve a
+ * {@link IPlatformCompatNative} IBinder for native code communicating with the platform compat
+ * service.
+ * @hide
+ */
+ public static final String PLATFORM_COMPAT_NATIVE_SERVICE = "platform_compat_native";
+
+ /**
* Service to capture a bugreport.
* @see #getSystemService(String)
* @see android.os.BugreportManager
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5c65238b3ef1..cfa3934b0cae 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -473,6 +473,14 @@ public class ConnectivityManager {
public static final int TETHERING_BLUETOOTH = 2;
/**
+ * Wifi P2p tethering type.
+ * Wifi P2p tethering is set through events automatically, and don't
+ * need to start from #startTethering(int, boolean, OnStartTetheringCallback).
+ * @hide
+ */
+ public static final int TETHERING_WIFI_P2P = 3;
+
+ /**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
* @hide
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 2cf2a6514e77..87295142bec4 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -416,7 +416,6 @@ public final class MacAddress implements Parcelable {
* @param mask MacAddress representing the mask to use during comparison.
* @return true if this MAC Address matches the given range.
*
- * @hide
*/
public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
Preconditions.checkNotNull(baseAddress);
@@ -430,7 +429,6 @@ public final class MacAddress implements Parcelable {
* IPv6 address per RFC 4862.
*
* @return A link-local Inet6Address constructed from the MAC address.
- * @hide
*/
public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() {
byte[] macEui48Bytes = toByteArray();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 3e325b748f51..e3259ffa9d47 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -57,6 +57,9 @@ public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
private static final int INVALID_UID = -1;
+ // Set to true when private DNS is broken.
+ private boolean mPrivateDnsBroken;
+
/**
* @hide
*/
@@ -86,6 +89,7 @@ public final class NetworkCapabilities implements Parcelable {
mUids = null;
mEstablishingVpnAppUid = INVALID_UID;
mSSID = null;
+ mPrivateDnsBroken = false;
}
/**
@@ -104,6 +108,7 @@ public final class NetworkCapabilities implements Parcelable {
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
mSSID = nc.mSSID;
+ mPrivateDnsBroken = nc.mPrivateDnsBroken;
}
/**
@@ -557,6 +562,9 @@ public final class NetworkCapabilities implements Parcelable {
}
if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
if (hasSignalStrength()) return "signalStrength";
+ if (isPrivateDnsBroken()) {
+ return "privateDnsBroken";
+ }
return null;
}
@@ -1443,7 +1451,8 @@ public final class NetworkCapabilities implements Parcelable {
&& equalsSpecifier(that)
&& equalsTransportInfo(that)
&& equalsUids(that)
- && equalsSSID(that));
+ && equalsSSID(that)
+ && equalsPrivateDnsBroken(that));
}
@Override
@@ -1460,7 +1469,8 @@ public final class NetworkCapabilities implements Parcelable {
+ (mSignalStrength * 29)
+ Objects.hashCode(mUids) * 31
+ Objects.hashCode(mSSID) * 37
- + Objects.hashCode(mTransportInfo) * 41;
+ + Objects.hashCode(mTransportInfo) * 41
+ + Objects.hashCode(mPrivateDnsBroken) * 43;
}
@Override
@@ -1479,6 +1489,7 @@ public final class NetworkCapabilities implements Parcelable {
dest.writeInt(mSignalStrength);
dest.writeArraySet(mUids);
dest.writeString(mSSID);
+ dest.writeBoolean(mPrivateDnsBroken);
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1498,6 +1509,7 @@ public final class NetworkCapabilities implements Parcelable {
netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
null /* ClassLoader, null for default */);
netCap.mSSID = in.readString();
+ netCap.mPrivateDnsBroken = in.readBoolean();
return netCap;
}
@Override
@@ -1555,6 +1567,10 @@ public final class NetworkCapabilities implements Parcelable {
sb.append(" SSID: ").append(mSSID);
}
+ if (mPrivateDnsBroken) {
+ sb.append(" Private DNS is broken");
+ }
+
sb.append("]");
return sb.toString();
}
@@ -1706,4 +1722,28 @@ public final class NetworkCapabilities implements Parcelable {
public boolean isMetered() {
return !hasCapability(NET_CAPABILITY_NOT_METERED);
}
+
+ /**
+ * Check if private dns is broken.
+ *
+ * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken.
+ * @hide
+ */
+ public boolean isPrivateDnsBroken() {
+ return mPrivateDnsBroken;
+ }
+
+ /**
+ * Set mPrivateDnsBroken to true when private dns is broken.
+ *
+ * @param broken the status of private DNS to be set.
+ * @hide
+ */
+ public void setPrivateDnsBroken(boolean broken) {
+ mPrivateDnsBroken = broken;
+ }
+
+ private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) {
+ return mPrivateDnsBroken == nc.mPrivateDnsBroken;
+ }
}
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 9ba3bd940a96..4ad52d5aa1bc 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -77,6 +77,12 @@ public class NetworkMisc implements Parcelable {
*/
public boolean skip464xlat;
+ /**
+ * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
+ * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
+ */
+ public boolean hasShownBroken;
+
public NetworkMisc() {
}
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 767c15caefd0..9c999b202797 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -113,6 +113,21 @@ public final class ConfigUpdate {
public static final String ACTION_UPDATE_CARRIER_ID_DB
= "android.os.action.UPDATE_CARRIER_ID_DB";
+ /**
+ * Broadcast intent action indicating that the updated emergency number database is available.
+ * <p>Extra: "VERSION" the numeric version of the new data. Devices should only install if the
+ * update version is newer than the current one.
+ * <p>Extra: "REQUIRED_HASH" the hash of the current update data.
+ * <p>Input: {@link android.content.Intent#getData} is URI of downloaded emergency number file.
+ * Devices should pick up the downloaded file and persist to the database
+ * {@code com.android.internal.telephony.emergency.EmergencyNumberTracker}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB =
+ "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
+
private ConfigUpdate() {
}
}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index d2f22bfac84a..ff8b13506201 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -29,7 +29,6 @@ import android.telephony.TelephonyManager;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
import android.telephony.euicc.EuiccManager.OtaStatus;
-import android.util.ArraySet;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -252,18 +251,6 @@ public abstract class EuiccService extends Service {
public static final int RESULT_FIRST_USER = 1;
/**
- * List of all valid resolution actions for validation purposes.
- * @hide
- */
- public static final ArraySet<String> RESOLUTION_ACTIONS;
- static {
- RESOLUTION_ACTIONS = new ArraySet<>();
- RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM);
- RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES);
- RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS);
- }
-
- /**
* Boolean extra for resolution actions indicating whether the user granted consent.
* This is used and set by the implementation and used in {@code EuiccOperation}.
*/
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index 72b0ad7a02bc..e0eb9af8b228 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -21,6 +21,7 @@ import android.util.Slog;
import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.HashMap;
import java.util.HashSet;
@@ -37,7 +38,7 @@ public final class ChangeReporter {
private static final String TAG = "CompatibilityChangeReporter";
private int mSource;
- private final class ChangeReport {
+ private static final class ChangeReport {
long mChangeId;
int mState;
@@ -65,9 +66,13 @@ public final class ChangeReporter {
@GuardedBy("mReportedChanges")
private final Map<Integer, Set<ChangeReport>> mReportedChanges;
+ // When true will of every time to debug (logcat).
+ private boolean mDebugLogAll;
+
public ChangeReporter(int source) {
mSource = source;
mReportedChanges = new HashMap<>();
+ mDebugLogAll = false;
}
/**
@@ -79,20 +84,76 @@ public final class ChangeReporter {
* @param state of the reported change - enabled/disabled/only logged
*/
public void reportChange(int uid, long changeId, int state) {
- ChangeReport report = new ChangeReport(changeId, state);
+ if (shouldWriteToStatsLog(uid, changeId, state)) {
+ StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId,
+ state, mSource);
+ }
+ if (shouldWriteToDebug(uid, changeId, state)) {
+ debugLog(uid, changeId, state);
+ }
+ markAsReported(uid, new ChangeReport(changeId, state));
+ }
+
+ /**
+ * Start logging all the time to logcat.
+ */
+ public void startDebugLogAll() {
+ mDebugLogAll = true;
+ }
+
+ /**
+ * Stop logging all the time to logcat.
+ */
+ public void stopDebugLogAll() {
+ mDebugLogAll = false;
+ }
+
+
+ /**
+ * Returns whether the next report should be logged to statsLog.
+ *
+ * @param uid affected by the change
+ * @param changeId the reported change id
+ * @param state of the reported change - enabled/disabled/only logged
+ * @return true if the report should be logged
+ */
+ @VisibleForTesting
+ public boolean shouldWriteToStatsLog(int uid, long changeId, int state) {
+ return !isAlreadyReported(uid, new ChangeReport(changeId, state));
+ }
+
+ /**
+ * Returns whether the next report should be logged to logcat.
+ *
+ * @param uid affected by the change
+ * @param changeId the reported change id
+ * @param state of the reported change - enabled/disabled/only logged
+ * @return true if the report should be logged
+ */
+ @VisibleForTesting
+ public boolean shouldWriteToDebug(int uid, long changeId, int state) {
+ return mDebugLogAll || !isAlreadyReported(uid, new ChangeReport(changeId, state));
+ }
+
+ private boolean isAlreadyReported(int uid, ChangeReport report) {
+ synchronized (mReportedChanges) {
+ Set<ChangeReport> reportedChangesForUid = mReportedChanges.get(uid);
+ if (reportedChangesForUid == null) {
+ return false;
+ } else {
+ return reportedChangesForUid.contains(report);
+ }
+ }
+ }
+
+ private void markAsReported(int uid, ChangeReport report) {
synchronized (mReportedChanges) {
Set<ChangeReport> reportedChangesForUid = mReportedChanges.get(uid);
if (reportedChangesForUid == null) {
mReportedChanges.put(uid, new HashSet<ChangeReport>());
reportedChangesForUid = mReportedChanges.get(uid);
}
- if (!reportedChangesForUid.contains(report)) {
- debugLog(uid, changeId, state);
- StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId,
- state, mSource);
- reportedChangesForUid.add(report);
- }
-
+ reportedChangesForUid.add(report);
}
}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 4099cfa51b33..8391ad2f12c2 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -49,9 +49,10 @@ interface IPlatformCompat
* you do not need to call this API directly. The change will be reported for you.
*
* @param changeId The ID of the compatibility change taking effect.
+ * @param userId The ID of the user that the operation is done for.
* @param packageName The package name of the app in question.
*/
- void reportChangeByPackageName(long changeId, in String packageName);
+ void reportChangeByPackageName(long changeId, in String packageName, int userId);
/**
* Reports that a compatibility change is affecting an app process now.
@@ -86,7 +87,7 @@ interface IPlatformCompat
* be called when implementing functionality on behalf of the affected app.
*
* <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name
- * instead of an {@link ApplicationInfo}
+ * and userId instead of an {@link ApplicationInfo}
* object, and finds an app info object based on the package name. Returns {@code true} if
* there is no installed package by that name.
*
@@ -100,9 +101,10 @@ interface IPlatformCompat
*
* @param changeId The ID of the compatibility change in question.
* @param packageName The package name of the app in question.
+ * @param userId The ID of the user that the operation is done for.
* @return {@code true} if the change is enabled for the current app.
*/
- boolean isChangeEnabledByPackageName(long changeId, in String packageName);
+ boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
/**
* Query if a given compatibility change is enabled for an app process. This method should
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 6270d89ca720..486d24c781d9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -169,7 +169,6 @@ cc_library_shared {
"android_media_AudioVolumeGroups.cpp",
"android_media_AudioVolumeGroupCallback.cpp",
"android_media_DeviceCallback.cpp",
- "android_media_JetPlayer.cpp",
"android_media_MediaMetricsJNI.cpp",
"android_media_MicrophoneInfo.cpp",
"android_media_midi.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 571c2cb6e172..9a90555041d7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -113,7 +113,6 @@ extern int register_android_media_AudioProductStrategies(JNIEnv *env);
extern int register_android_media_AudioVolumeGroups(JNIEnv *env);
extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env);
extern int register_android_media_MicrophoneInfo(JNIEnv *env);
-extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
extern int register_android_media_midi(JNIEnv *env);
@@ -1589,7 +1588,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_AudioProductStrategies),
REG_JNI(register_android_media_AudioVolumeGroups),
REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
- REG_JNI(register_android_media_JetPlayer),
REG_JNI(register_android_media_MicrophoneInfo),
REG_JNI(register_android_media_RemoteDisplay),
REG_JNI(register_android_media_ToneGenerator),
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b4c75715406..c17d7d13efc9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -772,6 +772,18 @@
android:permissionFlags="hardRestricted"
android:protectionLevel="dangerous" />
+ <!-- @SystemApi @TestApi Allows an application to forward cell broadcast messages to the cell
+ broadcast module. This is required in order to bind to the cell broadcast service, and
+ ensures that only the system can forward messages to it.
+
+ <p>Protection level: signature
+
+ @hide -->
+ <permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
+ android:label="@string/permlab_bindCellBroadcastService"
+ android:description="@string/permdesc_bindCellBroadcastService"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
messages and to register a content observer to get notifications when
a cell broadcast has been received and added to the database. For
@@ -4856,6 +4868,14 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.EmergencyNumberDbInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.os.action.UPDATE_EMERGENCY_NUMBER_DB" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR">
<intent-filter
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8336f54dbad4..5a287c1594f5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -387,6 +387,12 @@
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
+ Wifi P2P interfaces. If the device doesn't want to support tethering over Wifi P2p this
+ should be empty. An example would be "p2p-p2p.*" -->
+ <string-array translatable="false" name="config_tether_wifi_p2p_regexs">
+ </string-array>
+
+ <!-- List of regexpressions describing the interface (if any) that represent tetherable
WiMAX interfaces. If the device doesn't want to support tethering over Wifi this
should be empty. An example would be "softap.*" -->
<string-array translatable="false" name="config_tether_wimax_regexs">
@@ -441,6 +447,10 @@
-->
</string-array>
+ <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
+ <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastreceiver
+ </string>
+
<!-- If the mobile hotspot feature requires provisioning, a package name and class name
can be provided to launch a supported application that provisions the devices.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 152b131af8f5..936ff0cb7992 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -884,6 +884,16 @@
messages. This means the app could monitor or delete messages sent to your
device without showing them to you.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this.[CHAR LIMIT=NONE] -->
+ <string name="permlab_bindCellBroadcastService">Forward cell broadcast messages</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_bindCellBroadcastService">Allows the app to bind to the
+ cell broadcast module in order to forward cell broadcast messages
+ as they are received. Cell broadcast alerts are delivered in some
+ locations to warn you of emergency situations. Malicious apps may
+ interfere with the performance or operation of your device when an
+ emergency cell broadcast is received.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readCellBroadcasts">read cell broadcast messages</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3421,6 +3431,15 @@
<!-- 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 when the user connects to a mobile network without internet access. This is the notification's title. -->
+ <string name="mobile_no_internet">Mobile network has no internet access</string>
+
+ <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
+ <string name="other_networks_no_internet">Network has no internet access</string>
+
+ <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
+ <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</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 connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0bd5e4377c05..aacc74ff173b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -590,9 +590,12 @@
<java-symbol type="string" name="menu_space_shortcut_label" />
<java-symbol type="string" name="menu_shift_shortcut_label" />
<java-symbol type="string" name="menu_sym_shortcut_label" />
+ <java-symbol type="string" name="mobile_no_internet" />
<java-symbol type="string" name="notification_title" />
+ <java-symbol type="string" name="other_networks_no_internet" />
<java-symbol type="string" name="permission_request_notification_with_subtitle" />
<java-symbol type="string" name="prepend_shortcut_label" />
+ <java-symbol type="string" name="private_dns_broken_detailed" />
<java-symbol type="string" name="paste_as_plain_text" />
<java-symbol type="string" name="replace" />
<java-symbol type="string" name="undo" />
@@ -744,6 +747,7 @@
<java-symbol type="string" name="config_ethernet_iface_regex" />
<java-symbol type="array" name="config_ethernet_interfaces" />
<java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
+ <java-symbol type="string" name="cellbroadcast_default_package" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
<java-symbol type="string" name="config_mms_user_agent_profile_url" />
@@ -1914,6 +1918,7 @@
<java-symbol type="bool" name="config_tether_upstream_automatic" />
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
+ <java-symbol type="array" name="config_tether_wifi_p2p_regexs" />
<java-symbol type="array" name="config_usbHostBlacklist" />
<java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index f71c8b0558cf..2d1c61cc22fc 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -90,7 +90,7 @@
<shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
<!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
- <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296|83782|3011|73240" />
+ <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296|83782|3011|73240|72438" />
<!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
<shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}|4665" />
diff --git a/core/tests/PlatformCompatFramework/Android.bp b/core/tests/PlatformCompatFramework/Android.bp
new file mode 100644
index 000000000000..33802650fa12
--- /dev/null
+++ b/core/tests/PlatformCompatFramework/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+ name: "PlatformCompatFrameworkTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "junit",
+ "androidx.test.rules",
+ ],
+ platform_apis: true,
+}
diff --git a/core/tests/PlatformCompatFramework/AndroidManifest.xml b/core/tests/PlatformCompatFramework/AndroidManifest.xml
new file mode 100644
index 000000000000..4a6383b77000
--- /dev/null
+++ b/core/tests/PlatformCompatFramework/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.internal.compat">
+ <application android:label="ChangeReporterTest">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.compat"/>
+</manifest> \ No newline at end of file
diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS
new file mode 100644
index 000000000000..2b7cdb0cbce9
--- /dev/null
+++ b/core/tests/PlatformCompatFramework/OWNERS
@@ -0,0 +1,7 @@
+# Use this reviewer by default.
+platform-compat-eng+reviews@google.com
+
+andreionea@google.com
+atrost@google.com
+mathewi@google.com
+satayev@google.com
diff --git a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
new file mode 100644
index 000000000000..09bbe37bf292
--- /dev/null
+++ b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.internal.compat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class ChangeReporterTest {
+ @Test
+ public void testStatsLogOnce() {
+ ChangeReporter reporter = new ChangeReporter(0);
+ int myUid = 1022, otherUid = 1023;
+ long myChangeId = 500L, otherChangeId = 600L;
+ int myState = 1, otherState = 2;
+
+ assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ reporter.reportChange(myUid, myChangeId, myState);
+
+ // Same report will not be logged again.
+ assertFalse(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ // Other reports will be logged.
+ assertTrue(reporter.shouldWriteToStatsLog(otherUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToStatsLog(myUid, otherChangeId, myState));
+ assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, otherState));
+ }
+
+ @Test
+ public void testStatsLogAfterReset() {
+ ChangeReporter reporter = new ChangeReporter(0);
+ int myUid = 1022;
+ long myChangeId = 500L;
+ int myState = 1;
+
+ assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ reporter.reportChange(myUid, myChangeId, myState);
+
+ // Same report will not be logged again.
+ assertFalse(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ reporter.resetReportedChanges(myUid);
+
+ // Same report will be logged again after reset.
+ assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
+ }
+
+ @Test
+ public void testDebugLogOnce() {
+ ChangeReporter reporter = new ChangeReporter(0);
+ int myUid = 1022, otherUid = 1023;
+ long myChangeId = 500L, otherChangeId = 600L;
+ int myState = 1, otherState = 2;
+
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ reporter.reportChange(myUid, myChangeId, myState);
+
+ // Same report will not be logged again.
+ assertFalse(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ // Other reports will be logged.
+ assertTrue(reporter.shouldWriteToDebug(otherUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToDebug(myUid, otherChangeId, myState));
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, otherState));
+ }
+
+ @Test
+ public void testDebugLogAfterReset() {
+ ChangeReporter reporter = new ChangeReporter(0);
+ int myUid = 1022;
+ long myChangeId = 500L;
+ int myState = 1;
+
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ reporter.reportChange(myUid, myChangeId, myState);
+
+ // Same report will not be logged again.
+ assertFalse(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ reporter.resetReportedChanges(myUid);
+
+ // Same report will be logged again after reset.
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ }
+
+ @Test
+ public void testDebugLogWithLogAll() {
+ ChangeReporter reporter = new ChangeReporter(0);
+ int myUid = 1022;
+ long myChangeId = 500L;
+ int myState = 1;
+
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ reporter.reportChange(myUid, myChangeId, myState);
+
+ reporter.startDebugLogAll();
+ // Same report will be logged again.
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+
+ reporter.stopDebugLogAll();
+ assertFalse(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
+ }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
new file mode 100644
index 000000000000..1b5ad8868a01
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package android.app.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import org.junit.Test;
+
+public class PhoneTimeSuggestionTest {
+ private static final int PHONE_ID = 99999;
+
+ @Test
+ public void testEquals() {
+ PhoneTimeSuggestion one =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, one);
+
+ PhoneTimeSuggestion two =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, two);
+ assertEquals(two, one);
+
+ PhoneTimeSuggestion three =
+ new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+
+ // DebugInfo must not be considered in equals().
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+
+ @Test
+ public void testParcelable() {
+ PhoneTimeSuggestion one =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, roundTripParcelable(one));
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ one.addDebugInfo("This is debug info");
+ PhoneTimeSuggestion two = roundTripParcelable(one);
+ assertEquals(one.getDebugInfo(), two.getDebugInfo());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Parcelable> T roundTripParcelable(T one) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeTypedObject(one, 0);
+ parcel.setDataPosition(0);
+
+ T toReturn = (T) parcel.readTypedObject(PhoneTimeSuggestion.CREATOR);
+ parcel.recycle();
+ return toReturn;
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 54c548a7b174..14011373d2ed 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -125,6 +125,7 @@ applications that come with the platform
<permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/>
<permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
+ <permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/>
<permission name="android.permission.BIND_IMS_SERVICE"/>
<permission name="android.permission.BIND_TELEPHONY_DATA_SERVICE"/>
<permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/>
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 53bc65d711b0..bb731a8189f9 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -26,6 +27,8 @@ import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Map;
@@ -431,6 +434,50 @@ public class AudioSystem
public static final int DEAD_OBJECT = -6;
public static final int WOULD_BLOCK = -7;
+ /** @hide */
+ @IntDef({
+ SUCCESS,
+ ERROR,
+ BAD_VALUE,
+ INVALID_OPERATION,
+ PERMISSION_DENIED,
+ NO_INIT,
+ DEAD_OBJECT,
+ WOULD_BLOCK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AudioSystemError {}
+
+ /**
+ * Convert an int error value to its String value for readability.
+ * Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h,
+ * which map onto the native status_t type.
+ * @param error one of the java AudioSystem errors
+ * @return a human-readable string
+ */
+ public static String audioSystemErrorToString(@AudioSystemError int error) {
+ switch(error) {
+ case SUCCESS:
+ return "SUCCESS";
+ case ERROR:
+ return "ERROR";
+ case BAD_VALUE:
+ return "BAD_VALUE";
+ case INVALID_OPERATION:
+ return "INVALID_OPERATION";
+ case PERMISSION_DENIED:
+ return "PERMISSION_DENIED";
+ case NO_INIT:
+ return "NO_INIT";
+ case DEAD_OBJECT:
+ return "DEAD_OBJECT";
+ case WOULD_BLOCK:
+ return "WOULD_BLOCK";
+ default:
+ return ("unknown error:" + error);
+ }
+ }
+
/*
* AudioPolicyService methods
*/
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index b12e647acc4b..e85b3ff99104 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -17,18 +17,17 @@
package android.media;
-import java.io.FileDescriptor;
-import java.lang.ref.WeakReference;
-import java.lang.CloneNotSupportedException;
-
import android.annotation.UnsupportedAppUsage;
import android.content.res.AssetFileDescriptor;
-import android.os.Looper;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.util.AndroidRuntimeException;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.lang.ref.WeakReference;
+
/**
* JetPlayer provides access to JET content playback and control.
*
@@ -120,6 +119,9 @@ public class JetPlayer
private static JetPlayer singletonRef;
+ static {
+ System.loadLibrary("media_jni");
+ }
//--------------------------------
// Used exclusively by native code
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 39474e13a2d0..01f12500b77b 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -853,6 +853,10 @@ public class AudioPolicy {
Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
}
}
+
+ public void notifyUnregistration() {
+ setRegistration(null);
+ }
};
//==================================================
diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
index 107e7cd59ca2..1d581516e7b1 100644
--- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
+++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
@@ -34,4 +34,8 @@ oneway interface IAudioPolicyCallback {
// callback for volume events
void notifyVolumeAdjust(int adjustment);
+
+ // callback for unregistration (e.g. if policy couldn't automatically be re-registered after
+ // an audioserver crash)
+ void notifyUnregistration();
}
diff --git a/media/java/android/media/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
index 5b2ac9b64663..a2482040526d 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.aidl
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -16,4 +16,4 @@
package android.media.midi;
-parcelable MidiDeviceInfo cpp_header "media/MidiDeviceInfo.h";
+parcelable MidiDeviceInfo cpp_header "MidiDeviceInfo.h";
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 45ee210c80c9..e6c1c67b98e5 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -4,6 +4,7 @@ cc_library_shared {
srcs: [
"android_media_ImageWriter.cpp",
"android_media_ImageReader.cpp",
+ "android_media_JetPlayer.cpp",
"android_media_MediaCrypto.cpp",
"android_media_MediaCodec.cpp",
"android_media_MediaCodecList.cpp",
@@ -25,10 +26,12 @@ cc_library_shared {
"android_mtp_MtpDatabase.cpp",
"android_mtp_MtpDevice.cpp",
"android_mtp_MtpServer.cpp",
+ "JetPlayer.cpp",
],
shared_libs: [
"libandroid_runtime",
+ "libaudioclient",
"libnativehelper",
"libnativewindow",
"libutils",
@@ -53,6 +56,7 @@ cc_library_shared {
"libandroidfw",
"libhidlallocatorutils",
"libhidlbase",
+ "libsonivox",
"android.hardware.cas@1.0",
"android.hardware.cas.native@1.0",
"android.hidl.memory@1.0",
@@ -64,7 +68,10 @@ cc_library_shared {
"libmediadrm_headers",
],
- static_libs: ["libgrallocusage"],
+ static_libs: [
+ "libgrallocusage",
+ "libmedia_midiiowrapper",
+ ],
include_dirs: [
"frameworks/base/core/jni",
diff --git a/media/jni/JetPlayer.cpp b/media/jni/JetPlayer.cpp
new file mode 100644
index 000000000000..358feb7f73d9
--- /dev/null
+++ b/media/jni/JetPlayer.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "JetPlayer-C"
+
+#include <utils/Log.h>
+#include "JetPlayer.h"
+
+
+namespace android
+{
+
+static const int MIX_NUM_BUFFERS = 4;
+static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
+ mEventCallback(NULL),
+ mJavaJetPlayerRef(javaJetPlayer),
+ mTid(-1),
+ mRender(false),
+ mPaused(false),
+ mMaxTracks(maxTracks),
+ mEasData(NULL),
+ mIoWrapper(NULL),
+ mTrackBufferSize(trackBufferSize)
+{
+ ALOGV("JetPlayer constructor");
+ mPreviousJetStatus.currentUserID = -1;
+ mPreviousJetStatus.segmentRepeatCount = -1;
+ mPreviousJetStatus.numQueuedSegments = -1;
+ mPreviousJetStatus.paused = true;
+}
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::~JetPlayer()
+{
+ ALOGV("~JetPlayer");
+ release();
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::init()
+{
+ //Mutex::Autolock lock(&mMutex);
+
+ EAS_RESULT result;
+
+ // retrieve the EAS library settings
+ if (pLibConfig == NULL)
+ pLibConfig = EAS_Config();
+ if (pLibConfig == NULL) {
+ ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
+ return EAS_FAILURE;
+ }
+
+ // init the EAS library
+ result = EAS_Init(&mEasData);
+ if (result != EAS_SUCCESS) {
+ ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
+ mState = EAS_STATE_ERROR;
+ return result;
+ }
+ // init the JET library with the default app event controller range
+ result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
+ if (result != EAS_SUCCESS) {
+ ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
+ mState = EAS_STATE_ERROR;
+ return result;
+ }
+
+ // create the output AudioTrack
+ mAudioTrack = new AudioTrack();
+ status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
+ pLibConfig->sampleRate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ audio_channel_out_mask_from_count(pLibConfig->numChannels),
+ (size_t) mTrackBufferSize,
+ AUDIO_OUTPUT_FLAG_NONE);
+ if (status != OK) {
+ ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
+ mAudioTrack.clear();
+ mState = EAS_STATE_ERROR;
+ return EAS_FAILURE;
+ }
+
+ // create render and playback thread
+ {
+ Mutex::Autolock l(mMutex);
+ ALOGV("JetPlayer::init(): trying to start render thread");
+ mThread = new JetPlayerThread(this);
+ mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
+ mCondition.wait(mMutex);
+ }
+ if (mTid > 0) {
+ // render thread started, we're ready
+ ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
+ mState = EAS_STATE_READY;
+ } else {
+ ALOGE("JetPlayer::init(): failed to start render thread.");
+ mState = EAS_STATE_ERROR;
+ return EAS_FAILURE;
+ }
+
+ return EAS_SUCCESS;
+}
+
+void JetPlayer::setEventCallback(jetevent_callback eventCallback)
+{
+ Mutex::Autolock l(mMutex);
+ mEventCallback = eventCallback;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::release()
+{
+ ALOGV("JetPlayer::release()");
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ mRender = false;
+ if (mEasData) {
+ JET_Pause(mEasData);
+ JET_CloseFile(mEasData);
+ JET_Shutdown(mEasData);
+ EAS_Shutdown(mEasData);
+ }
+ delete mIoWrapper;
+ mIoWrapper = NULL;
+ if (mAudioTrack != 0) {
+ mAudioTrack->stop();
+ mAudioTrack->flush();
+ mAudioTrack.clear();
+ }
+ if (mAudioBuffer) {
+ delete mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mEasData = NULL;
+
+ return EAS_SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::render() {
+ EAS_RESULT result = EAS_FAILURE;
+ EAS_I32 count;
+ int temp;
+ bool audioStarted = false;
+
+ ALOGV("JetPlayer::render(): entering");
+
+ // allocate render buffer
+ mAudioBuffer =
+ new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
+
+ // signal main thread that we started
+ {
+ Mutex::Autolock l(mMutex);
+ mTid = gettid();
+ ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
+ mCondition.signal();
+ }
+
+ while (1) {
+
+ mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
+
+ if (mEasData == NULL) {
+ mMutex.unlock();
+ ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
+ goto threadExit;
+ }
+
+ // nothing to render, wait for client thread to wake us up
+ while (!mRender)
+ {
+ ALOGV("JetPlayer::render(): signal wait");
+ if (audioStarted) {
+ mAudioTrack->pause();
+ // we have to restart the playback once we start rendering again
+ audioStarted = false;
+ }
+ mCondition.wait(mMutex);
+ ALOGV("JetPlayer::render(): signal rx'd");
+ }
+
+ // render midi data into the input buffer
+ int num_output = 0;
+ EAS_PCM* p = mAudioBuffer;
+ for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
+ result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
+ if (result != EAS_SUCCESS) {
+ ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
+ }
+ p += count * pLibConfig->numChannels;
+ num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
+
+ // send events that were generated (if any) to the event callback
+ fireEventsFromJetQueue();
+ }
+
+ // update playback state
+ //ALOGV("JetPlayer::render(): updating state");
+ JET_Status(mEasData, &mJetStatus);
+ fireUpdateOnStatusChange();
+ mPaused = mJetStatus.paused;
+
+ mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
+
+ // check audio output track
+ if (mAudioTrack == NULL) {
+ ALOGE("JetPlayer::render(): output AudioTrack was not created");
+ goto threadExit;
+ }
+
+ // Write data to the audio hardware
+ //ALOGV("JetPlayer::render(): writing to audio output");
+ if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
+ ALOGE("JetPlayer::render(): Error in writing:%d",temp);
+ return temp;
+ }
+
+ // start audio output if necessary
+ if (!audioStarted) {
+ ALOGV("JetPlayer::render(): starting audio playback");
+ mAudioTrack->start();
+ audioStarted = true;
+ }
+
+ }//while (1)
+
+threadExit:
+ if (mAudioTrack != NULL) {
+ mAudioTrack->stop();
+ mAudioTrack->flush();
+ }
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ mMutex.lock();
+ mTid = -1;
+ mCondition.signal();
+ mMutex.unlock();
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up an update if any of the status fields has changed
+// precondition: mMutex locked
+void JetPlayer::fireUpdateOnStatusChange()
+{
+ if ( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
+ ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
+ if (mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_USERID_UPDATE,
+ mJetStatus.currentUserID,
+ mJetStatus.segmentRepeatCount,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
+ mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
+ }
+
+ if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
+ if (mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
+ mJetStatus.numQueuedSegments,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
+ }
+
+ if (mJetStatus.paused != mPreviousJetStatus.paused) {
+ if (mEventCallback) {
+ mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
+ mJetStatus.paused,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.paused = mJetStatus.paused;
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up all the JET events in the JET engine queue (until the queue is empty)
+// precondition: mMutex locked
+void JetPlayer::fireEventsFromJetQueue()
+{
+ if (!mEventCallback) {
+ // no callback, just empty the event queue
+ while (JET_GetEvent(mEasData, NULL, NULL)) { }
+ return;
+ }
+
+ EAS_U32 rawEvent;
+ while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
+ mEventCallback(
+ JetPlayer::JET_EVENT,
+ rawEvent,
+ -1,
+ mJavaJetPlayerRef);
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFile(const char* path)
+{
+ ALOGV("JetPlayer::loadFromFile(): path=%s", path);
+
+ Mutex::Autolock lock(mMutex);
+
+ delete mIoWrapper;
+ mIoWrapper = new MidiIoWrapper(path);
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
+ if (result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ return( result );
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
+{
+ ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
+
+ Mutex::Autolock lock(mMutex);
+
+ delete mIoWrapper;
+ mIoWrapper = new MidiIoWrapper(fd, offset, length);
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
+ if (result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ return( result );
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::closeFile()
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_CloseFile(mEasData);
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::play()
+{
+ ALOGV("JetPlayer::play(): entering");
+ Mutex::Autolock lock(mMutex);
+
+ EAS_RESULT result = JET_Play(mEasData);
+
+ mPaused = false;
+ mRender = true;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+
+ fireUpdateOnStatusChange();
+
+ // wake up render thread
+ ALOGV("JetPlayer::play(): wakeup render thread");
+ mCondition.signal();
+
+ return result;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::pause()
+{
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ EAS_RESULT result = JET_Pause(mEasData);
+
+ mRender = false;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+ fireUpdateOnStatusChange();
+
+
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID)
+{
+ ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
+ segmentNum, libNum, repeatCount, transpose);
+ Mutex::Autolock lock(mMutex);
+ return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
+ userID);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlags(mEasData, muteFlags, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::triggerClip(int clipId)
+{
+ ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
+ Mutex::Autolock lock(mMutex);
+ return JET_TriggerClip(mEasData, clipId);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::clearQueue()
+{
+ ALOGV("JetPlayer::clearQueue");
+ Mutex::Autolock lock(mMutex);
+ return JET_Clear_Queue(mEasData);
+}
+
+//-------------------------------------------------------------------------------------------------
+void JetPlayer::dump()
+{
+}
+
+void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
+{
+ if (pJetStatus!=NULL)
+ ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
+ "paused=%d",
+ pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
+ pJetStatus->numQueuedSegments, pJetStatus->paused);
+ else
+ ALOGE(">> JET player status is NULL");
+}
+
+
+} // end namespace android
diff --git a/media/jni/JetPlayer.h b/media/jni/JetPlayer.h
new file mode 100644
index 000000000000..bb569bcad7be
--- /dev/null
+++ b/media/jni/JetPlayer.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef JETPLAYER_H_
+#define JETPLAYER_H_
+
+#include <utils/threads.h>
+
+#include <libsonivox/jet.h>
+#include <libsonivox/eas_types.h>
+#include <media/AudioTrack.h>
+#include <media/MidiIoWrapper.h>
+
+
+namespace android {
+
+typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
+
+class JetPlayer {
+
+public:
+
+ // to keep in sync with the JetPlayer class constants
+ // defined in frameworks/base/media/java/android/media/JetPlayer.java
+ static const int JET_EVENT = 1;
+ static const int JET_USERID_UPDATE = 2;
+ static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
+ static const int JET_PAUSE_UPDATE = 4;
+
+ JetPlayer(void *javaJetPlayer,
+ int maxTracks = 32,
+ int trackBufferSize = 1200);
+ ~JetPlayer();
+ int init();
+ int release();
+
+ int loadFromFile(const char* url);
+ int loadFromFD(const int fd, const long long offset, const long long length);
+ int closeFile();
+ int play();
+ int pause();
+ int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID);
+ int setMuteFlags(EAS_U32 muteFlags, bool sync);
+ int setMuteFlag(int trackNum, bool muteFlag, bool sync);
+ int triggerClip(int clipId);
+ int clearQueue();
+
+ void setEventCallback(jetevent_callback callback);
+
+ int getMaxTracks() { return mMaxTracks; };
+
+
+private:
+ int render();
+ void fireUpdateOnStatusChange();
+ void fireEventsFromJetQueue();
+
+ JetPlayer() {} // no default constructor
+ void dump();
+ void dumpJetStatus(S_JET_STATUS* pJetStatus);
+
+ jetevent_callback mEventCallback;
+
+ void* mJavaJetPlayerRef;
+ Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
+ pid_t mTid;
+ Condition mCondition;
+ volatile bool mRender;
+ bool mPaused;
+
+ EAS_STATE mState;
+ int* mMemFailedVar;
+
+ int mMaxTracks; // max number of MIDI tracks, usually 32
+ EAS_DATA_HANDLE mEasData;
+ MidiIoWrapper* mIoWrapper;
+ EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
+ sp<AudioTrack> mAudioTrack; // and we play it in this audio track
+ int mTrackBufferSize;
+ S_JET_STATUS mJetStatus;
+ S_JET_STATUS mPreviousJetStatus;
+
+ class JetPlayerThread : public Thread {
+ public:
+ JetPlayerThread(JetPlayer *player) : mPlayer(player) {
+ }
+
+ protected:
+ virtual ~JetPlayerThread() {}
+
+ private:
+ JetPlayer *mPlayer;
+
+ bool threadLoop() {
+ int result;
+ result = mPlayer->render();
+ return false;
+ }
+
+ JetPlayerThread(const JetPlayerThread &);
+ JetPlayerThread &operator=(const JetPlayerThread &);
+ };
+
+ sp<JetPlayerThread> mThread;
+
+}; // end class JetPlayer
+
+} // end namespace android
+
+
+
+#endif /*JETPLAYER_H_*/
diff --git a/core/jni/android_media_JetPlayer.cpp b/media/jni/android_media_JetPlayer.cpp
index da116bf7c96a..8a05f85e4285 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/media/jni/android_media_JetPlayer.cpp
@@ -27,7 +27,7 @@
#include "core_jni_helpers.h"
#include <utils/Log.h>
-#include <media/JetPlayer.h>
+#include "JetPlayer.h"
using namespace android;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d24edc7552ae..ec0ce8759571 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1436,6 +1436,7 @@ static int register_android_media_MediaPlayer(JNIEnv *env)
}
extern int register_android_media_ImageReader(JNIEnv *env);
extern int register_android_media_ImageWriter(JNIEnv *env);
+extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_Crypto(JNIEnv *env);
extern int register_android_media_Drm(JNIEnv *env);
extern int register_android_media_Descrambler(JNIEnv *env);
@@ -1475,6 +1476,11 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
goto bail;
}
+ if (register_android_media_JetPlayer(env) < 0) {
+ ALOGE("ERROR: JetPlayer native registration failed");
+ goto bail;
+ }
+
if (register_android_media_MediaPlayer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index 58317edbea68..8f3e12e98bab 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -17,6 +17,7 @@ cc_library_shared {
srcs: [
"amidi.cpp",
+ "MidiDeviceInfo.cpp",
":IMidiDeviceServer.aidl",
],
@@ -31,12 +32,14 @@ cc_library_shared {
"-fvisibility=hidden",
],
+ header_libs: [
+ "media_ndk_headers",
+ ],
+
shared_libs: [
"liblog",
"libbinder",
"libutils",
- "libmedia",
- "libmediandk",
"libandroid_runtime",
],
diff --git a/media/native/midi/MidiDeviceInfo.cpp b/media/native/midi/MidiDeviceInfo.cpp
new file mode 100644
index 000000000000..ac68d26c935b
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "MidiDeviceInfo"
+
+#include <MidiDeviceInfo.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+// The constant values need to be kept in sync with MidiDeviceInfo.java.
+// static
+const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
+const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
+const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
+const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
+const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
+
+String16 MidiDeviceInfo::getProperty(const char* propertyName) {
+ String16 value;
+ if (mProperties.getString(String16(propertyName), &value)) {
+ return value;
+ } else {
+ return String16();
+ }
+}
+
+#define RETURN_IF_FAILED(calledOnce) \
+ { \
+ status_t returnStatus = calledOnce; \
+ if (returnStatus) { \
+ ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+ return returnStatus; \
+ } \
+ }
+
+status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
+ // Needs to be kept in sync with code in MidiDeviceInfo.java
+ RETURN_IF_FAILED(parcel->writeInt32(mType));
+ RETURN_IF_FAILED(parcel->writeInt32(mId));
+ RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
+ RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
+ RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
+ RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
+ RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
+ RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+ // This corresponds to "extra" properties written by Java code
+ RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+ return OK;
+}
+
+status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
+ // Needs to be kept in sync with code in MidiDeviceInfo.java
+ RETURN_IF_FAILED(parcel->readInt32(&mType));
+ RETURN_IF_FAILED(parcel->readInt32(&mId));
+ int32_t inputPortCount;
+ RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
+ int32_t outputPortCount;
+ RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
+ RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
+ RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
+ int32_t isPrivate;
+ RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
+ mIsPrivate = isPrivate == 1;
+ RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
+ // Ignore "extra" properties as they may contain Java Parcelables
+ return OK;
+}
+
+status_t MidiDeviceInfo::readStringVector(
+ const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
+ std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
+ status_t result = parcel->readString16Vector(&v);
+ if (result != OK) return result;
+ vectorPtr->clear();
+ if (v.get() != nullptr) {
+ for (const auto& iter : *v) {
+ if (iter.get() != nullptr) {
+ vectorPtr->push_back(*iter);
+ } else {
+ vectorPtr->push_back(String16());
+ }
+ }
+ } else {
+ vectorPtr->resize(defaultLength);
+ }
+ return OK;
+}
+
+status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
+ std::vector<String16> v;
+ for (size_t i = 0; i < vector.size(); ++i) {
+ v.push_back(vector[i]);
+ }
+ return parcel->writeString16Vector(v);
+}
+
+// Vector does not define operator==
+static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
+ if (lhs.size() != rhs.size()) return false;
+ for (size_t i = 0; i < lhs.size(); ++i) {
+ if (lhs[i] != rhs[i]) return false;
+ }
+ return true;
+}
+
+bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+ return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
+ areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
+ areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
+ lhs.mProperties == rhs.mProperties &&
+ lhs.mIsPrivate == rhs.mIsPrivate);
+}
+
+} // namespace midi
+} // namespace media
+} // namespace android
diff --git a/media/native/midi/MidiDeviceInfo.h b/media/native/midi/MidiDeviceInfo.h
new file mode 100644
index 000000000000..5b4a241323d7
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+class MidiDeviceInfo : public Parcelable {
+public:
+ MidiDeviceInfo() = default;
+ virtual ~MidiDeviceInfo() = default;
+ MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ int getType() const { return mType; }
+ int getUid() const { return mId; }
+ bool isPrivate() const { return mIsPrivate; }
+ const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
+ const Vector<String16>& getOutputPortNames() const { return mOutputPortNames; }
+ String16 getProperty(const char* propertyName);
+
+ // The constants need to be kept in sync with MidiDeviceInfo.java
+ enum {
+ TYPE_USB = 1,
+ TYPE_VIRTUAL = 2,
+ TYPE_BLUETOOTH = 3,
+ };
+ static const char* const PROPERTY_NAME;
+ static const char* const PROPERTY_MANUFACTURER;
+ static const char* const PROPERTY_PRODUCT;
+ static const char* const PROPERTY_VERSION;
+ static const char* const PROPERTY_SERIAL_NUMBER;
+ static const char* const PROPERTY_ALSA_CARD;
+ static const char* const PROPERTY_ALSA_DEVICE;
+
+ friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
+ friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+ return !(lhs == rhs);
+ }
+
+private:
+ status_t readStringVector(
+ const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
+ status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
+
+ int32_t mType;
+ int32_t mId;
+ Vector<String16> mInputPortNames;
+ Vector<String16> mOutputPortNames;
+ os::PersistableBundle mProperties;
+ bool mIsPrivate;
+};
+
+} // namespace midi
+} // namespace media
+} // namespace android
+
+#endif // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 1e9a194d76c8..e7c4d9983f74 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -26,7 +26,7 @@
#include <core_jni_helpers.h>
#include "android/media/midi/BpMidiDeviceServer.h"
-#include "media/MidiDeviceInfo.h"
+#include "MidiDeviceInfo.h"
#include "include/amidi/AMidi.h"
#include "amidi_internal.h"
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 7c1af4a81f9d..ae8cb3a47a05 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -110,3 +110,31 @@ llndk_library {
symbol_file: "libandroid_net.map.txt",
unversioned: true,
}
+
+
+// Aidl library for platform compat.
+cc_library_shared {
+ name: "lib-platform-compat-native-api",
+ defaults: ["libandroid_defaults"],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ local_include_dirs: ["aidl"],
+ export_aidl_headers: true,
+ },
+ srcs: [
+ ":platform-compat-native-aidl",
+ ],
+ export_include_dirs: ["aidl"],
+}
+
+filegroup {
+ name: "platform-compat-native-aidl",
+ srcs: [
+ "aidl/com/android/internal/compat/IPlatformCompatNative.aidl",
+ ],
+ path: "aidl",
+} \ No newline at end of file
diff --git a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
new file mode 100644
index 000000000000..347e4e8ebe4b
--- /dev/null
+++ b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
@@ -0,0 +1,93 @@
+/*
+ * 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.internal.compat;
+
+/**
+ * Platform native private API for talking with the PlatformCompat service.
+ *
+ * <p> Should be used for gating and logging from non-app processes running cpp code.
+ * For app processes please use android.compat.Compatibility API.
+ *
+ * {@hide}
+ */
+interface IPlatformCompatNative
+{
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)},
+ * you do not need to call this API directly. The change will be reported for you.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param userId The ID of the user that the operation is done for.
+ * @param packageName The package name of the app in question.
+ */
+ void reportChangeByPackageName(long changeId, @utf8InCpp String packageName, int userId);
+
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)},
+ * you do not need to call this API directly. The change will be reported for you.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param uid The UID of the app in question.
+ */
+ void reportChangeByUid(long changeId, int uid);
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p>Returns {@code true} if there is no installed package by the provided package name.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method
+ * returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>It will also report the change as {@link #reportChange(long, String)} would, so there is
+ * no need to call that method directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param packageName The package name of the app in question.
+ * @param userId The ID of the user that the operation is done for.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName, int userId);
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p> Returns {@code true} if there are no installed packages for the required UID, or if the
+ * change is enabled for ALL of the installed packages associated with the provided UID. Please
+ * use a more specific API if you want a different behaviour for multi-package UIDs.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method
+ * returns {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is
+ * no need to call that method directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param uid The UID of the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ boolean isChangeEnabledByUid(long changeId, int uid);
+} \ No newline at end of file
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index aef6a3cdf5c8..0d8e69b447e8 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -10,4 +10,5 @@ jminjie@google.com
satk@google.com
shuoq@google.com
refuhoo@google.com
-nazaninb@google.com \ No newline at end of file
+nazaninb@google.com
+sarahchin@google.com
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 81c5bcd47981..642dc82c4d28 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -35,7 +35,6 @@ import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -477,11 +476,11 @@ public class CaptivePortalLoginActivity extends Activity {
}
private static void logd(String s) {
- Rlog.d(TAG, s);
+ Log.d(TAG, s);
}
private static void loge(String s) {
- Rlog.d(TAG, s);
+ Log.d(TAG, s);
}
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
index 02c61d778086..46b1d5fe27be 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -19,7 +19,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.Rlog;
import android.text.TextUtils;
import android.util.Log;
@@ -27,7 +26,6 @@ import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
/**
@@ -44,7 +42,7 @@ public class CustomConfigLoader {
private static final String INTER_GROUP_DELIMITER = "\\s*:\\s*";
private static final String TAG = CustomConfigLoader.class.getSimpleName();
- private static final boolean VDBG = Rlog.isLoggable(TAG, Log.VERBOSE);
+ private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
/**
* loads and parses the carrier config, return a list of carrier action for the given signal
@@ -70,7 +68,7 @@ public class CustomConfigLoader {
// return an empty list if no match found
List<Integer> actionList = new ArrayList<>();
if (carrierConfigManager == null) {
- Rlog.e(TAG, "load carrier config failure with carrier config manager uninitialized");
+ Log.e(TAG, "load carrier config failure with carrier config manager uninitialized");
return actionList;
}
PersistableBundle b = carrierConfigManager.getConfig();
@@ -101,8 +99,8 @@ public class CustomConfigLoader {
.EXTRA_DEFAULT_NETWORK_AVAILABLE_KEY, false));
break;
default:
- Rlog.e(TAG, "load carrier config failure with un-configured key: " +
- intent.getAction());
+ Log.e(TAG, "load carrier config failure with un-configured key: "
+ + intent.getAction());
break;
}
if (!ArrayUtils.isEmpty(configs)) {
@@ -111,12 +109,12 @@ public class CustomConfigLoader {
matchConfig(config, arg1, arg2, actionList);
if (!actionList.isEmpty()) {
// return the first match
- if (VDBG) Rlog.d(TAG, "found match action list: " + actionList.toString());
+ if (VDBG) Log.d(TAG, "found match action list: " + actionList.toString());
return actionList;
}
}
}
- Rlog.d(TAG, "no matching entry for signal: " + intent.getAction() + "arg1: " + arg1
+ Log.d(TAG, "no matching entry for signal: " + intent.getAction() + "arg1: " + arg1
+ "arg2: " + arg2);
}
return actionList;
@@ -166,7 +164,7 @@ public class CustomConfigLoader {
try {
actionList.add(Integer.parseInt(idx));
} catch (NumberFormatException e) {
- Rlog.e(TAG, "NumberFormatException(string: " + idx + " config:" + config + "): "
+ Log.e(TAG, "NumberFormatException(string: " + idx + " config:" + config + "): "
+ e);
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0e9183940f22..bdfa21742854 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -127,6 +127,9 @@
<!-- Summary for Connected wifi network without internet -->
<string name="wifi_connected_no_internet">Connected, no internet</string>
+ <!-- Summary for connected network without internet due to private dns validation failed [CHAR LIMIT=NONE] -->
+ <string name="private_dns_broken">Private DNS server cannot be accessed</string>
+
<!-- Summary for connected wifi network with partial internet connectivity [CHAR LIMIT=50] -->
<string name="wifi_limited_connection">Limited connection</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f16fb1c91b7c..9e71189913d6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -50,6 +50,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -1569,7 +1570,13 @@ public class AccessPoint implements Comparable<AccessPoint> {
NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
return context.getString(R.string.wifi_limited_connection);
} else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
- return context.getString(R.string.wifi_connected_no_internet);
+ final String mode = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.PRIVATE_DNS_MODE);
+ if (nc.isPrivateDnsBroken()) {
+ return context.getString(R.string.private_dns_broken);
+ } else {
+ return context.getString(R.string.wifi_connected_no_internet);
+ }
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 5352936d7224..b11585a73946 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -31,6 +31,7 @@ import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiSsid;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
import com.android.settingslib.R;
@@ -163,7 +164,13 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
statusLabel = mContext.getString(R.string.wifi_limited_connection);
return;
} else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
- statusLabel = mContext.getString(R.string.wifi_status_no_internet);
+ final String mode = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.PRIVATE_DNS_MODE);
+ if (networkCapabilities.isPrivateDnsBroken()) {
+ statusLabel = mContext.getString(R.string.private_dns_broken);
+ } else {
+ statusLabel = mContext.getString(R.string.wifi_status_no_internet);
+ }
return;
}
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 591af82ecb4e..a25c4f7e36ec 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -436,13 +436,13 @@
<string name="data_connection_lte_plus">LTE+</string>
<!-- Content description of the data connection type 5Ge. [CHAR LIMIT=NONE] -->
- <string name="data_connection_5ge" translate="false">5Ge</string>
+ <string name="data_connection_5ge" translatable="false">5Ge</string>
<!-- Content description of the data connection type 5G. [CHAR LIMIT=NONE] -->
- <string name="data_connection_5g" translate="false">5G</string>
+ <string name="data_connection_5g" translatable="false">5G</string>
<!-- Content description of the data connection type 5G+. [CHAR LIMIT=NONE] -->
- <string name="data_connection_5g_plus" translate="false">5G+</string>
+ <string name="data_connection_5g_plus" translatable="false">5G+</string>
<!-- Content description of the data connection type CDMA. [CHAR LIMIT=NONE] -->
<string name="data_connection_cdma">1X</string>
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
new file mode 100644
index 000000000000..dc88fd4014da
--- /dev/null
+++ b/packages/Tethering/Android.bp
@@ -0,0 +1,72 @@
+//
+// 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.
+//
+
+java_defaults {
+ name: "TetheringAndroidLibraryDefaults",
+ platform_apis: true,
+ srcs: [
+ "src/**/*.java",
+ ":framework-tethering-shared-srcs",
+ ":services-tethering-shared-srcs",
+ ],
+ static_libs: [
+ "androidx.annotation_annotation",
+ "tethering-client",
+ ],
+ manifest: "AndroidManifestBase.xml",
+}
+
+// Build tethering static library, used to compile both variants of the tethering.
+android_library {
+ name: "TetheringApiCurrentLib",
+ defaults: ["TetheringAndroidLibraryDefaults"],
+}
+
+// Common defaults for compiling the actual APK.
+java_defaults {
+ name: "TetheringAppDefaults",
+ platform_apis: true,
+ privileged: true,
+ resource_dirs: [
+ "res",
+ ],
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
+}
+
+// Non-updatable tethering running in the system server process for devices not using the module
+// TODO: build in-process tethering APK here.
+
+// Updatable tethering packaged as an application
+android_app {
+ name: "Tethering",
+ defaults: ["TetheringAppDefaults"],
+ static_libs: ["TetheringApiCurrentLib"],
+ certificate: "networkstack",
+ manifest: "AndroidManifest.xml",
+ use_embedded_native_libs: true,
+ // The permission configuration *must* be included to ensure security of the device
+ required: ["NetworkPermissionConfig"],
+}
+
+// This group will be removed when tethering migration is done.
+filegroup {
+ name: "tethering-services-srcs",
+ srcs: [
+ "src/com/android/server/connectivity/tethering/TetheringConfiguration.java",
+ ],
+}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
new file mode 100644
index 000000000000..eb51593e4538
--- /dev/null
+++ b/packages/Tethering/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.tethering"
+ android:sharedUserId="android.uid.networkstack">
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+ <application
+ android:process="com.android.networkstack.process"
+ android:extractNativeLibs="false"
+ android:persistent="true">
+ </application>
+</manifest>
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
new file mode 100644
index 000000000000..b9cac1994359
--- /dev/null
+++ b/packages/Tethering/AndroidManifestBase.xml
@@ -0,0 +1,29 @@
+<?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.tethering"
+ android:versionCode="1"
+ android:versionName="R-initial">
+ <application
+ android:label="Tethering"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true"
+ android:usesCleartextTraffic="true">
+ </application>
+</manifest>
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
new file mode 100644
index 000000000000..5b01b1e038c3
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+
+// AIDL interfaces between the core system and the tethering mainline module.
+aidl_interface {
+ name: "tethering-aidl-interfaces",
+ local_include_dir: "src",
+ srcs: [
+ "src/android/net/ITetheringConnector.aidl",
+ ],
+ backend: {
+ ndk: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
+}
+
+java_library {
+ name: "tethering-client",
+ platform_apis: true,
+ static_libs: [
+ "tethering-aidl-interfaces-java",
+ ],
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
new file mode 100644
index 000000000000..443481e33f8d
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+/** @hide */
+oneway interface ITetheringConnector {
+}
diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags
new file mode 100644
index 000000000000..77fc024a8755
--- /dev/null
+++ b/packages/Tethering/proguard.flags
@@ -0,0 +1 @@
+#TBD
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
new file mode 100644
index 000000000000..37e679dbeb63
--- /dev/null
+++ b/packages/Tethering/res/values/config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!--
+ OEMs that wish to change the below settings must do so via a runtime resource overlay package
+ and *NOT* by changing this file. This file is part of the tethering mainline module.
+ -->
+</resources>
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 1907892c4d87..77097271c454 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -28,6 +28,7 @@ import static com.android.internal.R.array.config_tether_bluetooth_regexs;
import static com.android.internal.R.array.config_tether_dhcp_range;
import static com.android.internal.R.array.config_tether_upstream_types;
import static com.android.internal.R.array.config_tether_usb_regexs;
+import static com.android.internal.R.array.config_tether_wifi_p2p_regexs;
import static com.android.internal.R.array.config_tether_wifi_regexs;
import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period;
@@ -81,10 +82,11 @@ public class TetheringConfiguration {
"192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
};
- private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
+ private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
public final String[] tetherableUsbRegexs;
public final String[] tetherableWifiRegexs;
+ public final String[] tetherableWifiP2pRegexs;
public final String[] tetherableBluetoothRegexs;
public final boolean isDunRequired;
public final boolean chooseUpstreamAutomatically;
@@ -110,6 +112,7 @@ public class TetheringConfiguration {
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
+ tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs);
tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
isDunRequired = checkDunRequired(ctx, subId);
@@ -130,28 +133,44 @@ public class TetheringConfiguration {
configLog.log(toString());
}
+ /** Check whether input interface belong to usb.*/
public boolean isUsb(String iface) {
return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
}
+ /** Check whether input interface belong to wifi.*/
public boolean isWifi(String iface) {
return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
}
+ /** Check whether this interface is Wifi P2P interface. */
+ public boolean isWifiP2p(String iface) {
+ return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
+ }
+
+ /** Check whether using legacy mode for wifi P2P. */
+ public boolean isWifiP2pLegacyTetheringMode() {
+ return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0);
+ }
+
+ /** Check whether input interface belong to bluetooth.*/
public boolean isBluetooth(String iface) {
return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
}
+ /** Check whether no ui entitlement application is available.*/
public boolean hasMobileHotspotProvisionApp() {
return !TextUtils.isEmpty(provisioningAppNoUi);
}
+ /** Does the dumping.*/
public void dump(PrintWriter pw) {
pw.print("subId: ");
pw.println(subId);
dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
+ dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
pw.print("isDunRequired: ");
@@ -173,11 +192,13 @@ public class TetheringConfiguration {
pw.println(enableLegacyDhcpServer);
}
+ /** Returns the string representation of this object.*/
public String toString() {
final StringJoiner sj = new StringJoiner(" ");
sj.add(String.format("subId:%d", subId));
sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
+ sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs)));
sj.add(String.format("tetherableBluetoothRegexs:%s",
makeString(tetherableBluetoothRegexs)));
sj.add(String.format("isDunRequired:%s", isDunRequired));
@@ -196,7 +217,7 @@ public class TetheringConfiguration {
if (values != null) {
final StringJoiner sj = new StringJoiner(", ", "[", "]");
- for (String value : values) { sj.add(value); }
+ for (String value : values) sj.add(value);
pw.print(sj.toString());
} else {
pw.print("null");
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
new file mode 100644
index 000000000000..089bbd31d9f3
--- /dev/null
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -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.
+//
+
+android_test {
+ name: "TetheringTests",
+ certificate: "platform",
+ srcs: ["src/**/*.java"],
+ test_suites: ["device-tests"],
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "mockito-target-extended-minus-junit4",
+ "TetheringApiCurrentLib",
+ "testables",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+}
+
+// This group would be removed when tethering migration is done.
+filegroup {
+ name: "tethering-tests-src",
+ srcs: [
+ "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java",
+ ],
+}
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
new file mode 100644
index 000000000000..049ff6d415f3
--- /dev/null
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?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.tethering.tests.unit">
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.tethering.tests.unit"
+ android:label="Tethering service tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index e28296354d2a..9f9221f3010d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -24,7 +24,12 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
+import static com.android.internal.R.array.config_tether_bluetooth_regexs;
+import static com.android.internal.R.array.config_tether_dhcp_range;
import static com.android.internal.R.array.config_tether_upstream_types;
+import static com.android.internal.R.array.config_tether_usb_regexs;
+import static com.android.internal.R.array.config_tether_wifi_regexs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -86,7 +91,9 @@ public class TetheringConfigurationTest {
}
@Override
- public Resources getResources() { return mResources; }
+ public Resources getResources() {
+ return mResources;
+ }
@Override
public Object getSystemService(String name) {
@@ -105,17 +112,13 @@ public class TetheringConfigurationTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
- .thenReturn(new String[0]);
- when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
- .thenReturn(new String[0]);
- when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
+ when(mResources.getStringArray(config_tether_dhcp_range)).thenReturn(new String[0]);
+ when(mResources.getStringArray(config_tether_usb_regexs)).thenReturn(new String[0]);
+ when(mResources.getStringArray(config_tether_wifi_regexs))
.thenReturn(new String[]{ "test_wlan\\d" });
- when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
+ when(mResources.getStringArray(config_tether_bluetooth_regexs)).thenReturn(new String[0]);
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]);
- when(mResources.getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app))
+ when(mResources.getStringArray(config_mobile_hotspot_provision_app))
.thenReturn(new String[0]);
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
@@ -297,19 +300,16 @@ public class TetheringConfigurationTest {
private void setUpResourceForSubId() {
when(mResourcesForSubId.getStringArray(
- com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]);
+ config_tether_dhcp_range)).thenReturn(new String[0]);
when(mResourcesForSubId.getStringArray(
- com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
+ config_tether_usb_regexs)).thenReturn(new String[0]);
when(mResourcesForSubId.getStringArray(
- com.android.internal.R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d" });
+ config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" });
when(mResourcesForSubId.getStringArray(
- com.android.internal.R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
+ config_tether_bluetooth_regexs)).thenReturn(new String[0]);
when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]);
when(mResourcesForSubId.getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app))
- .thenReturn(PROVISIONING_APP_NAME);
+ config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME);
}
}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index ffbf1ae38635..ef071a43aa3e 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -249,6 +249,8 @@ message SystemMessage {
NOTE_NETWORK_LOGGED_IN = 744;
// A partial connectivity network was detected during network validation
NOTE_NETWORK_PARTIAL_CONNECTIVITY = 745;
+ // Private DNS is broken in strict mode
+ NOTE_NETWORK_PRIVATE_DNS_BROKEN = 746;
// 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 16432212d8e2..58fb0bfd48e4 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -20,6 +20,7 @@ java_library_static {
":vold_aidl",
":gsiservice_aidl",
":platform-compat-config",
+ ":tethering-services-srcs",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
"java/com/android/server/policy/EventLogTags.logtags",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0bb72cb9d554..ce0e9e7e56cf 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -26,6 +26,7 @@ import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
@@ -528,6 +529,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 45;
/**
+ * Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
+ * Both of the arguments are bitmasks, and the value of bits come from
+ * INetworkMonitor.NETWORK_VALIDATION_PROBE_*.
+ * arg1 = A bitmask to describe which probes are completed.
+ * arg2 = A bitmask to describe which probes are successful.
+ */
+ public static final int EVENT_PROBE_STATUS_CHANGED = 46;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -2663,6 +2673,41 @@ public class ConnectivityService extends IConnectivityManager.Stub
switch (msg.what) {
default:
return false;
+ case EVENT_PROBE_STATUS_CHANGED: {
+ final Integer netId = (Integer) msg.obj;
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+ if (nai == null) {
+ break;
+ }
+ final boolean probePrivateDnsCompleted =
+ ((msg.arg1 & NETWORK_VALIDATION_PROBE_PRIVDNS) != 0);
+ final boolean privateDnsBroken =
+ ((msg.arg2 & NETWORK_VALIDATION_PROBE_PRIVDNS) == 0);
+ if (probePrivateDnsCompleted) {
+ if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
+ nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
+ final int oldScore = nai.getCurrentScore();
+ updateCapabilities(oldScore, nai, nai.networkCapabilities);
+ }
+ // Only show the notification when the private DNS is broken and the
+ // PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
+ if (privateDnsBroken && !nai.networkMisc.hasShownBroken) {
+ showNetworkNotification(nai, NotificationType.PRIVATE_DNS_BROKEN);
+ }
+ nai.networkMisc.hasShownBroken = privateDnsBroken;
+ } else if (nai.networkCapabilities.isPrivateDnsBroken()) {
+ // If probePrivateDnsCompleted is false but nai.networkCapabilities says
+ // private DNS is broken, it means this network is being reevaluated.
+ // Either probing private DNS is not necessary any more or it hasn't been
+ // done yet. In either case, the networkCapabilities should be updated to
+ // reflect the new status.
+ nai.networkCapabilities.setPrivateDnsBroken(false);
+ final int oldScore = nai.getCurrentScore();
+ updateCapabilities(oldScore, nai, nai.networkCapabilities);
+ nai.networkMisc.hasShownBroken = false;
+ }
+ break;
+ }
case EVENT_NETWORK_TESTED: {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
@@ -2705,14 +2750,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
if (valid) {
handleFreshlyValidatedNetwork(nai);
- // Clear NO_INTERNET, PARTIAL_CONNECTIVITY and LOST_INTERNET
- // notifications if network becomes valid.
+ // Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
+ // LOST_INTERNET notifications if network becomes valid.
mNotifier.clearNotification(nai.network.netId,
NotificationType.NO_INTERNET);
mNotifier.clearNotification(nai.network.netId,
NotificationType.LOST_INTERNET);
mNotifier.clearNotification(nai.network.netId,
NotificationType.PARTIAL_CONNECTIVITY);
+ mNotifier.clearNotification(nai.network.netId,
+ NotificationType.PRIVATE_DNS_BROKEN);
+ // If network becomes valid, the hasShownBroken should be reset for
+ // that network so that the notification will be fired when the private
+ // DNS is broken again.
+ nai.networkMisc.hasShownBroken = false;
}
} else if (partialConnectivityChanged) {
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -2863,6 +2914,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
+ public void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) {
+ mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+ EVENT_PROBE_STATUS_CHANGED,
+ probesCompleted, probesSucceeded, new Integer(mNetId)));
+ }
+
+ @Override
public void showProvisioningNotification(String action, String packageName) {
final Intent intent = new Intent(action);
intent.setPackage(packageName);
@@ -3679,6 +3737,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
// High priority because it is only displayed for explicitly selected networks.
highPriority = true;
break;
+ case PRIVATE_DNS_BROKEN:
+ action = Settings.ACTION_WIRELESS_SETTINGS;
+ // High priority because we should let user know why there is no internet.
+ highPriority = true;
+ break;
case LOST_INTERNET:
action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
// High priority because it could help the user avoid unexpected data usage.
@@ -3696,7 +3759,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
Intent intent = new Intent(action);
- if (type != NotificationType.LOGGED_IN) {
+ if (type != NotificationType.LOGGED_IN && type != NotificationType.PRIVATE_DNS_BROKEN) {
intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.android.settings",
@@ -5162,6 +5225,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
ns.assertValidFromUid(Binder.getCallingUid());
}
+ private void ensureValid(NetworkCapabilities nc) {
+ ensureValidNetworkSpecifier(nc);
+ if (nc.isPrivateDnsBroken()) {
+ throw new IllegalArgumentException("Can't request broken private DNS");
+ }
+ }
+
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
@@ -5195,7 +5265,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
}
- ensureValidNetworkSpecifier(networkCapabilities);
+ ensureValid(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), type);
@@ -5337,7 +5407,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
// can't request networks.
restrictBackgroundRequestForCaller(nc);
- ensureValidNetworkSpecifier(nc);
+ ensureValid(nc);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -5355,7 +5425,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
- ensureValidNetworkSpecifier(networkCapabilities);
+ ensureValid(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
Binder.getCallingPid(), Binder.getCallingUid());
@@ -5841,6 +5911,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
newNc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
}
+ newNc.setPrivateDnsBroken(nai.networkCapabilities.isPrivateDnsBroken());
return newNc;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e26cbc4487f9..055a4bde8a78 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1018,7 +1018,14 @@ public class AudioService extends IAudioService.Stub
synchronized (mAudioPolicies) {
for (AudioPolicyProxy policy : mAudioPolicies.values()) {
- policy.connectMixes();
+ final int status = policy.connectMixes();
+ if (status != AudioSystem.SUCCESS) {
+ // note that PERMISSION_DENIED may also indicate trouble getting to APService
+ Log.e(TAG, "onAudioServerDied: error "
+ + AudioSystem.audioSystemErrorToString(status)
+ + " when connecting mixes for policy " + policy.toLogFriendlyString());
+ policy.release();
+ }
}
}
@@ -7007,16 +7014,8 @@ public class AudioService extends IAudioService.Stub
}
public void binderDied() {
- synchronized (mAudioPolicies) {
- Log.i(TAG, "audio policy " + mPolicyCallback + " died");
- release();
- mAudioPolicies.remove(mPolicyCallback.asBinder());
- }
- if (mIsVolumeController) {
- synchronized (mExtVolumeControllerLock) {
- mExtVolumeController = null;
- }
- }
+ Log.i(TAG, "audio policy " + mPolicyCallback + " died");
+ release();
}
String getRegistrationId() {
@@ -7040,9 +7039,20 @@ public class AudioService extends IAudioService.Stub
Log.e(TAG, "Fail to unregister Audiopolicy callback from MediaProjection");
}
}
+ if (mIsVolumeController) {
+ synchronized (mExtVolumeControllerLock) {
+ mExtVolumeController = null;
+ }
+ }
final long identity = Binder.clearCallingIdentity();
AudioSystem.registerPolicyMixes(mMixes, false);
Binder.restoreCallingIdentity(identity);
+ synchronized (mAudioPolicies) {
+ mAudioPolicies.remove(mPolicyCallback.asBinder());
+ }
+ try {
+ mPolicyCallback.notifyUnregistration();
+ } catch (RemoteException e) { }
}
boolean hasMixAffectingUsage(int usage, int excludedFlags) {
@@ -7093,7 +7103,7 @@ public class AudioService extends IAudioService.Stub
}
}
- int connectMixes() {
+ @AudioSystem.AudioSystemError int connectMixes() {
final long identity = Binder.clearCallingIdentity();
int status = AudioSystem.registerPolicyMixes(mMixes, true);
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 8a7dcc12baae..9ac9955493cc 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -19,6 +19,7 @@ package com.android.server.compat;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.os.UserHandle;
import android.util.Slog;
import android.util.StatsLog;
@@ -53,8 +54,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public void reportChangeByPackageName(long changeId, String packageName) {
- ApplicationInfo appInfo = getApplicationInfo(packageName);
+ public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
}
@@ -79,8 +80,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public boolean isChangeEnabledByPackageName(long changeId, String packageName) {
- ApplicationInfo appInfo = getApplicationInfo(packageName);
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
}
@@ -95,7 +96,8 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
boolean enabled = true;
for (String packageName : packages) {
- enabled = enabled && isChangeEnabledByPackageName(changeId, packageName);
+ enabled = enabled && isChangeEnabledByPackageName(changeId, packageName,
+ UserHandle.getUserId(uid));
}
return enabled;
}
@@ -126,9 +128,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
mChangeReporter.resetReportedChanges(appInfo.uid);
}
- private ApplicationInfo getApplicationInfo(String packageName) {
+ private ApplicationInfo getApplicationInfo(String packageName, int userId) {
try {
- return mContext.getPackageManager().getApplicationInfo(packageName, 0);
+ return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "No installed package " + packageName);
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java
new file mode 100644
index 000000000000..85dfbf411667
--- /dev/null
+++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java
@@ -0,0 +1,50 @@
+/*
+ * 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.compat;
+
+import com.android.internal.compat.IPlatformCompatNative;
+
+/**
+ * @hide
+ */
+public class PlatformCompatNative extends IPlatformCompatNative.Stub {
+ private final PlatformCompat mPlatformCompat;
+
+ public PlatformCompatNative(PlatformCompat platformCompat) {
+ mPlatformCompat = platformCompat;
+ }
+
+ @Override
+ public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ mPlatformCompat.reportChangeByPackageName(changeId, packageName, userId);
+ }
+
+ @Override
+ public void reportChangeByUid(long changeId, int uid) {
+ mPlatformCompat.reportChangeByUid(changeId, uid);
+ }
+
+ @Override
+ public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName, userId);
+ }
+
+ @Override
+ public boolean isChangeEnabledByUid(long changeId, int uid) {
+ return mPlatformCompat.isChangeEnabledByUid(changeId, uid);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 077c4057a3a0..d13e6753d1b0 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -53,7 +53,8 @@ public class NetworkNotificationManager {
NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN),
PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
- SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN);
+ SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
+ PRIVATE_DNS_BROKEN(SystemMessage.NOTE_NETWORK_PRIVATE_DNS_BROKEN);
public final int eventId;
@@ -175,13 +176,23 @@ public class NetworkNotificationManager {
}
Resources r = Resources.getSystem();
- CharSequence title;
- CharSequence details;
+ final CharSequence title;
+ final CharSequence details;
int icon = getIcon(transportType, notifyType);
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
details = r.getString(R.string.wifi_no_internet_detailed);
+ } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
+ if (transportType == TRANSPORT_CELLULAR) {
+ title = r.getString(R.string.mobile_no_internet);
+ } else if (transportType == TRANSPORT_WIFI) {
+ title = r.getString(R.string.wifi_no_internet,
+ WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
+ } else {
+ title = r.getString(R.string.other_networks_no_internet);
+ }
+ details = r.getString(R.string.private_dns_broken_detailed);
} else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
&& transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.network_partial_connectivity,
@@ -357,8 +368,10 @@ public class NetworkNotificationManager {
}
switch (t) {
case SIGN_IN:
- return 5;
+ return 6;
case PARTIAL_CONNECTIVITY:
+ return 5;
+ case PRIVATE_DNS_BROKEN:
return 4;
case NO_INTERNET:
return 3;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 5fd5c4bebb2a..b3804c4d7ec5 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -30,6 +30,7 @@ import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_INVALID;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
@@ -77,6 +78,9 @@ import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.net.util.VersionedBroadcastListener;
import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -290,6 +294,7 @@ public class Tethering extends BaseNetworkObserver {
filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mContext.registerReceiver(mStateReceiver, filter, null, handler);
filter = new IntentFilter();
@@ -354,6 +359,8 @@ public class Tethering extends BaseNetworkObserver {
if (cfg.isWifi(iface)) {
return TETHERING_WIFI;
+ } else if (cfg.isWifiP2p(iface)) {
+ return TETHERING_WIFI_P2P;
} else if (cfg.isUsb(iface)) {
return TETHERING_USB;
} else if (cfg.isBluetooth(iface)) {
@@ -527,6 +534,7 @@ public class Tethering extends BaseNetworkObserver {
public void untetherAll() {
stopTethering(TETHERING_WIFI);
+ stopTethering(TETHERING_WIFI_P2P);
stopTethering(TETHERING_USB);
stopTethering(TETHERING_BLUETOOTH);
}
@@ -713,6 +721,8 @@ public class Tethering extends BaseNetworkObserver {
handleConnectivityAction(intent);
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
handleWifiApAction(intent);
+ } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
+ handleWifiP2pAction(intent);
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
mLog.log("OBSERVED configuration changed");
updateConfiguration();
@@ -789,6 +799,39 @@ public class Tethering extends BaseNetworkObserver {
}
}
}
+
+ private void handleWifiP2pAction(Intent intent) {
+ if (mConfig.isWifiP2pLegacyTetheringMode()) return;
+
+ final WifiP2pInfo p2pInfo =
+ (WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
+ final WifiP2pGroup group =
+ (WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
+
+ if (VDBG) {
+ Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
+ }
+
+ if (p2pInfo == null) return;
+ // When a p2p group is disconnected, p2pInfo would be cleared.
+ // group is still valid for detecting whether this device is group owner.
+ if (group == null || !group.isGroupOwner()
+ || TextUtils.isEmpty(group.getInterface())) return;
+
+ synchronized (Tethering.this.mPublicSync) {
+ // Enter below only if this device is Group Owner with a valid interface.
+ if (p2pInfo.groupFormed) {
+ TetherState tetherState = mTetherStates.get(group.getInterface());
+ if (tetherState == null
+ || (tetherState.lastState != IpServer.STATE_TETHERED
+ && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
+ enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
+ }
+ } else {
+ disableWifiP2pIpServingLocked(group.getInterface());
+ }
+ }
+ }
}
@VisibleForTesting
@@ -823,14 +866,11 @@ public class Tethering extends BaseNetworkObserver {
}
}
- private void disableWifiIpServingLocked(String ifname, int apState) {
- mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState);
-
- // Regardless of whether we requested this transition, the AP has gone
- // down. Don't try to tether again unless we're requested to do so.
- // TODO: Remove this altogether, once Wi-Fi reliably gives us an
- // interface name with every broadcast.
- mWifiTetherRequested = false;
+ private void disableWifiIpServingLockedCommon(int tetheringType, String ifname, int apState) {
+ mLog.log("Canceling WiFi tethering request -"
+ + " type=" + tetheringType
+ + " interface=" + ifname
+ + " state=" + apState);
if (!TextUtils.isEmpty(ifname)) {
final TetherState ts = mTetherStates.get(ifname);
@@ -842,7 +882,7 @@ public class Tethering extends BaseNetworkObserver {
for (int i = 0; i < mTetherStates.size(); i++) {
final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
- if (ipServer.interfaceType() == TETHERING_WIFI) {
+ if (ipServer.interfaceType() == tetheringType) {
ipServer.unwanted();
return;
}
@@ -853,6 +893,20 @@ public class Tethering extends BaseNetworkObserver {
: "specified interface: " + ifname));
}
+ private void disableWifiIpServingLocked(String ifname, int apState) {
+ // Regardless of whether we requested this transition, the AP has gone
+ // down. Don't try to tether again unless we're requested to do so.
+ // TODO: Remove this altogether, once Wi-Fi reliably gives us an
+ // interface name with every broadcast.
+ mWifiTetherRequested = false;
+
+ disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
+ }
+
+ private void disableWifiP2pIpServingLocked(String ifname) {
+ disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+ }
+
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
// Map wifiIpMode values to IpServer.Callback serving states, inferring
// from mWifiTetherRequested as a final "best guess".
@@ -870,7 +924,7 @@ public class Tethering extends BaseNetworkObserver {
}
if (!TextUtils.isEmpty(ifname)) {
- maybeTrackNewInterfaceLocked(ifname, TETHERING_WIFI);
+ maybeTrackNewInterfaceLocked(ifname);
changeInterfaceState(ifname, ipServingMode);
} else {
mLog.e(String.format(
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 7bdc8a32815a..9dbbf16e7734 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.Slog;
import android.util.TimestampedValue;
@@ -48,9 +48,8 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
// @NonNull after initialize()
private Callback mCallback;
- // NITZ state.
- @Nullable private TimestampedValue<Long> mLastNitzTime;
-
+ // Last phone suggestion.
+ @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
// Information about the last time signal received: Used when toggling auto-time.
@Nullable private TimestampedValue<Long> mLastSystemClockTime;
@@ -65,46 +64,40 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
- public void suggestTime(@NonNull TimeSignal timeSignal) {
- if (!TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId())) {
- Slog.w(TAG, "Ignoring signal from unsupported source: " + timeSignal);
- return;
- }
-
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
// NITZ logic
- TimestampedValue<Long> newNitzUtcTime = timeSignal.getUtcTime();
- boolean nitzTimeIsValid = validateNewNitzTime(newNitzUtcTime, mLastNitzTime);
- if (!nitzTimeIsValid) {
+ boolean timeSuggestionIsValid =
+ validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
+ if (!timeSuggestionIsValid) {
return;
}
// Always store the last NITZ value received, regardless of whether we go on to use it to
// update the system clock. This is so that we can validate future NITZ signals.
- mLastNitzTime = newNitzUtcTime;
+ mLastPhoneSuggestion = timeSuggestion;
// System clock update logic.
// Historically, Android has sent a telephony broadcast only when setting the time using
// NITZ.
- final boolean sendNetworkBroadcast =
- TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId());
+ final boolean sendNetworkBroadcast = true;
- final TimestampedValue<Long> newUtcTime = newNitzUtcTime;
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
}
- private static boolean validateNewNitzTime(TimestampedValue<Long> newNitzUtcTime,
- TimestampedValue<Long> lastNitzTime) {
+ private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
+ @Nullable PhoneTimeSuggestion lastSuggestion) {
- if (lastNitzTime != null) {
- long referenceTimeDifference =
- TimestampedValue.referenceTimeDifference(newNitzUtcTime, lastNitzTime);
+ if (lastSuggestion != null) {
+ long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
+ newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
// Out of order or bogus.
Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+ " referenceTimeDifference=" + referenceTimeDifference
- + " lastNitzTime=" + lastNitzTime
- + " newNitzUtcTime=" + newNitzUtcTime);
+ + " lastSuggestion=" + lastSuggestion
+ + " newSuggestion=" + newSuggestion);
return false;
}
}
@@ -182,7 +175,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
@Override
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
- pw.println("mLastNitzTime=" + mLastNitzTime);
+ pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
pw.println("mLastSystemClockTimeSendNetworkBroadcast="
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 9c830003cab4..ee42279f7d50 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -96,14 +96,14 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
@Override
- public void suggestTime(@NonNull TimeSignal timeSignal) {
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
enforceSetTimePermission();
Objects.requireNonNull(timeSignal);
long idToken = Binder.clearCallingIdentity();
try {
synchronized (mStrategyLock) {
- mTimeDetectorStrategy.suggestTime(timeSignal);
+ mTimeDetectorStrategy.suggestPhoneTime(timeSignal);
}
} finally {
Binder.restoreCallingIdentity(idToken);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index e050865d96c7..7c2a945854f5 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,7 +18,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.TimestampedValue;
@@ -72,7 +72,7 @@ public interface TimeDetectorStrategy {
void initialize(@NonNull Callback callback);
/** Process the suggested time. */
- void suggestTime(@NonNull TimeSignal timeSignal);
+ void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionToggle(boolean enabled);
diff --git a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
new file mode 100644
index 000000000000..852f70779f77
--- /dev/null
+++ b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
@@ -0,0 +1,39 @@
+/*
+ * 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.updates;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+/**
+ * Emergency Number Database Install Receiver.
+ */
+public class EmergencyNumberDbInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ private static final String TAG = "EmergencyNumberDbInstallReceiver";
+
+ public EmergencyNumberDbInstallReceiver() {
+ super("/data/misc/emergencynumberdb", "emergency_number_db", "metadata/", "version");
+ }
+
+ @Override
+ protected void postInstall(Context context, Intent intent) {
+ Slog.i(TAG, "Emergency number database is updated in file partition");
+ // TODO Send a notification to EmergencyNumberTracker for updating of emergency number db.
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5c1dfef925cd..f465855017cd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -89,6 +89,7 @@ import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
import com.android.server.compat.PlatformCompat;
+import com.android.server.compat.PlatformCompatNative;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
@@ -639,8 +640,10 @@ public final class SystemServer {
// Platform compat service is used by ActivityManagerService, PackageManagerService, and
// possibly others in the future. b/135010838.
traceBeginAndSlog("PlatformCompat");
- ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE,
- new PlatformCompat(mSystemContext));
+ PlatformCompat platformCompat = new PlatformCompat(mSystemContext);
+ ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
+ ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
+ new PlatformCompatNative(platformCompat));
traceEnd();
// Wait for installd to finish starting up so that it has a chance to
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 1ca96ed80e5e..6a871aa81543 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -5,6 +5,7 @@ java_library_static {
"dnsresolver_aidl_interface-V2-java",
"netd_aidl_interface-java",
"networkstack-client",
+ "tethering-client",
],
}
@@ -17,3 +18,11 @@ filegroup {
"java/android/net/netlink/*.java",
],
}
+
+filegroup {
+ name: "services-tethering-shared-srcs",
+ srcs: [
+ ":framework-annotations",
+ "java/android/net/util/SharedLog.java"
+ ],
+}
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 6a6a1307723e..3d79bba7bbe3 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -93,6 +93,8 @@ public class IpServer extends StateMachine {
private static final int USB_PREFIX_LENGTH = 24;
private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
+ private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
+ private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
// TODO: have PanService use some visible version of this constant
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
@@ -403,6 +405,9 @@ public class IpServer extends StateMachine {
} else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
ipAsString = getRandomWifiIPv4Address();
prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
+ } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI_P2P) {
+ ipAsString = WIFI_P2P_IFACE_ADDR;
+ prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
} else {
// BT configures the interface elsewhere: only start DHCP.
final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
index 31a2556f2041..ca07630d3e63 100644
--- a/services/net/java/android/net/netlink/InetDiagMessage.java
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -26,6 +26,7 @@ import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.NETLINK_INET_DIAG;
+import android.annotation.Nullable;
import android.net.util.SocketUtils;
import android.system.ErrnoException;
import android.util.Log;
@@ -53,7 +54,35 @@ public class InetDiagMessage extends NetlinkMessage {
private static final int TIMEOUT_MS = 500;
public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
- InetSocketAddress remote, int family, short flags) {
+ InetSocketAddress remote, int family, short flags) {
+ return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
+ 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
+ }
+
+ /**
+ * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
+ * if local and remote are not both null or both non-null.
+ *
+ * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
+ * IPPROTO_UDP, or IPPROTO_UDPLITE.
+ * @param local local socket address of the target socket. This will be packed into a
+ * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+ * local or remote address is null.
+ * @param remote remote socket address of the target socket. This will be packed into a
+ * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+ * local or remote address is null.
+ * @param family the ip family of the request message. This should be set to either AF_INET or
+ * AF_INET6 for IPv4 or IPv6 sockets respectively.
+ * @param flags message flags. See &lt;linux_src&gt;/include/uapi/linux/netlink.h.
+ * @param pad for raw socket protocol specification.
+ * @param idiagExt a set of flags defining what kind of extended information to report.
+ * @param state a bit mask that defines a filter of socket states.
+ *
+ * @return bytes array representation of the message
+ **/
+ public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
+ @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
+ int state) throws NullPointerException {
final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
byteBuffer.order(ByteOrder.nativeOrder());
@@ -63,9 +92,9 @@ public class InetDiagMessage extends NetlinkMessage {
nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
nlMsgHdr.nlmsg_flags = flags;
nlMsgHdr.pack(byteBuffer);
+ final StructInetDiagReqV2 inetDiagReqV2 =
+ new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
- final StructInetDiagReqV2 inetDiagReqV2 = new StructInetDiagReqV2(protocol, local, remote,
- family);
inetDiagReqV2.pack(byteBuffer);
return bytes;
}
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
index 49a93258e714..2268113044d5 100644
--- a/services/net/java/android/net/netlink/StructInetDiagReqV2.java
+++ b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
@@ -16,10 +16,10 @@
package android.net.netlink;
-import static java.nio.ByteOrder.BIG_ENDIAN;
+import android.annotation.Nullable;
+
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
/**
* struct inet_diag_req_v2
@@ -40,41 +40,58 @@ import java.nio.ByteOrder;
public class StructInetDiagReqV2 {
public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
- private final byte sdiag_family;
- private final byte sdiag_protocol;
- private final StructInetDiagSockId id;
- private final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
-
+ private final byte mSdiagFamily;
+ private final byte mSdiagProtocol;
+ private final byte mIdiagExt;
+ private final byte mPad;
+ private final StructInetDiagSockId mId;
+ private final int mState;
+ public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
- int family) {
- sdiag_family = (byte) family;
- sdiag_protocol = (byte) protocol;
- id = new StructInetDiagSockId(local, remote);
+ int family) {
+ this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
+ INET_DIAG_REQ_V2_ALL_STATES);
+ }
+
+ public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
+ @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
+ throws NullPointerException {
+ mSdiagFamily = (byte) family;
+ mSdiagProtocol = (byte) protocol;
+ // Request for all sockets if no specific socket is requested. Specify the local and remote
+ // socket address information for target request socket.
+ if ((local == null) != (remote == null)) {
+ throw new NullPointerException("Local and remote must be both null or both non-null");
+ }
+ mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
+ mPad = (byte) pad;
+ mIdiagExt = (byte) extension;
+ mState = state;
}
public void pack(ByteBuffer byteBuffer) {
// The ByteOrder must have already been set by the caller.
- byteBuffer.put((byte) sdiag_family);
- byteBuffer.put((byte) sdiag_protocol);
- byteBuffer.put((byte) 0);
- byteBuffer.put((byte) 0);
- byteBuffer.putInt(INET_DIAG_REQ_V2_ALL_STATES);
- id.pack(byteBuffer);
+ byteBuffer.put((byte) mSdiagFamily);
+ byteBuffer.put((byte) mSdiagProtocol);
+ byteBuffer.put((byte) mIdiagExt);
+ byteBuffer.put((byte) mPad);
+ byteBuffer.putInt(mState);
+ if (mId != null) mId.pack(byteBuffer);
}
@Override
public String toString() {
- final String familyStr = NetlinkConstants.stringForAddressFamily(sdiag_family);
- final String protocolStr = NetlinkConstants.stringForAddressFamily(sdiag_protocol);
+ final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
+ final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
return "StructInetDiagReqV2{ "
+ "sdiag_family{" + familyStr + "}, "
+ "sdiag_protocol{" + protocolStr + "}, "
- + "idiag_ext{" + 0 + ")}, "
- + "pad{" + 0 + "}, "
- + "idiag_states{" + Integer.toHexString(INET_DIAG_REQ_V2_ALL_STATES) + "}, "
- + id.toString()
+ + "idiag_ext{" + mIdiagExt + ")}, "
+ + "pad{" + mPad + "}, "
+ + "idiag_states{" + Integer.toHexString(mState) + "}, "
+ + ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
+ "}";
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index 9e000770fe42..d79795593456 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
@@ -45,6 +45,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
.setActualTimeUtc(2018, 1, 1, 12, 0, 0)
.build();
+ private static final int ARBITRARY_PHONE_ID = 123456;
+
private Script mScript;
@Before
@@ -53,30 +55,32 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestTime_nitz_timeDetectionEnabled() {
+ public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ PhoneTimeSuggestion timeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
final int clockIncrement = 1000;
long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
mScript.simulateTimePassing(clockIncrement)
- .simulateTimeSignalReceived(timeSignal)
+ .simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
}
@Test
- public void testSuggestTime_systemClockThreshold() {
+ public void testSuggestPhoneTime_systemClockThreshold() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThresholdMillis = 1000;
mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThresholdMillis)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
final int clockIncrement = 100;
// Increment the the device clocks to simulate the passage of time.
@@ -86,7 +90,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
// Send the first time signal. It should be used.
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
// Now send another time signal, but one that is too similar to the last one and should be
@@ -95,9 +99,9 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + underThresholdMillis);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulateTimePassing(clockIncrement)
- .simulateTimeSignalReceived(timeSignal2)
+ .simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now send another time signal, but one that is on the threshold and so should be used.
@@ -105,42 +109,44 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
- TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+ PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimePassing(clockIncrement);
long expectSystemClockMillis3 =
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
- mScript.simulateTimeSignalReceived(timeSignal3)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
}
@Test
- public void testSuggestTime_nitz_timeDetectionDisabled() {
+ public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(false);
- TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- mScript.simulateTimeSignalReceived(timeSignal)
+ PhoneTimeSuggestion timeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
- public void testSuggestTime_nitz_invalidNitzReferenceTimesIgnored() {
+ public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Initialize the strategy / device with a time set from NITZ.
mScript.simulateTimePassing(100);
long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
// The UTC time increment should be larger than the system clock update threshold so we
@@ -152,8 +158,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
- mScript.simulateTimeSignalReceived(timeSignal2)
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now supply a new signal that has an obviously bogus reference time : substantially in the
@@ -162,8 +168,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis);
- TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
- mScript.simulateTimeSignalReceived(timeSignal3)
+ PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking();
// Just to prove validUtcTimeMillis is valid.
@@ -172,13 +178,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
validReferenceTimeMillis, validUtcTimeMillis);
long expectedSystemClockMillis4 =
TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
- TimeSignal timeSignal4 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime4);
- mScript.simulateTimeSignalReceived(timeSignal4)
+ PhoneTimeSuggestion timeSuggestion4 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
}
@Test
- public void testSuggestTime_timeDetectionToggled() {
+ public void testSuggestPhoneTime_timeDetectionToggled() {
Scenario scenario = SCENARIO_1;
final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000;
@@ -186,15 +192,16 @@ public class SimpleTimeZoneDetectorStrategyTest {
.pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(false);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing.
mScript.simulateTimePassing(clockIncrementMillis);
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasNotSetAndResetCallTracking();
// Simulate more time passing.
@@ -216,7 +223,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -226,7 +233,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
- mScript.simulateTimeSignalReceived(timeSignal2)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Turn on auto time detection.
@@ -234,17 +241,6 @@ public class SimpleTimeZoneDetectorStrategyTest {
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
}
- @Test
- public void testSuggestTime_unknownSource() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
-
- TimeSignal timeSignal = scenario.createTimeSignalForActual("unknown");
- mScript.simulateTimeSignalReceived(timeSignal)
- .verifySystemClockWasNotSetAndResetCallTracking();
- }
-
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -407,8 +403,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mFakeCallback.peekSystemClockMillis();
}
- Script simulateTimeSignalReceived(TimeSignal timeSignal) {
- mSimpleTimeDetectorStrategy.suggestTime(timeSignal);
+ Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
+ mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
return this;
}
@@ -466,10 +462,10 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mActualTimeMillis;
}
- TimeSignal createTimeSignalForActual(String sourceId) {
+ PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
TimestampedValue<Long> time = new TimestampedValue<>(
mInitialDeviceRealtimeMillis, mActualTimeMillis);
- return new TimeSignal(sourceId, time);
+ return new PhoneTimeSuggestion(phoneId, time);
}
static class Builder {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 45fef764482f..37da01824e88 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -28,7 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.TimestampedValue;
@@ -67,10 +67,10 @@ public class TimeDetectorServiceTest {
public void testStubbedCall_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeSignal timeSignal = createNitzTimeSignal();
+ PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
try {
- mTimeDetectorService.suggestTime(timeSignal);
+ mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
} finally {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
@@ -78,15 +78,15 @@ public class TimeDetectorServiceTest {
}
@Test
- public void testSuggestTime() {
+ public void testSuggestPhoneTime() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeSignal timeSignal = createNitzTimeSignal();
- mTimeDetectorService.suggestTime(timeSignal);
+ PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
+ mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
verify(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
- mStubbedTimeDetectorStrategy.verifySuggestTimeCalled(timeSignal);
+ mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
}
@Test
@@ -115,15 +115,16 @@ public class TimeDetectorServiceTest {
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
}
- private static TimeSignal createNitzTimeSignal() {
+ private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
+ int phoneId = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
- return new TimeSignal(TimeSignal.SOURCE_ID_NITZ, timeValue);
+ return new PhoneTimeSuggestion(phoneId, timeValue);
}
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
- private TimeSignal mLastSuggestedTime;
+ private PhoneTimeSuggestion mLastPhoneSuggestion;
private Boolean mLastAutoTimeDetectionToggle;
private boolean mDumpCalled;
@@ -132,9 +133,9 @@ public class TimeDetectorServiceTest {
}
@Override
- public void suggestTime(TimeSignal timeSignal) {
+ public void suggestPhoneTime(PhoneTimeSuggestion timeSuggestion) {
resetCallTracking();
- mLastSuggestedTime = timeSignal;
+ mLastPhoneSuggestion = timeSuggestion;
}
@Override
@@ -150,13 +151,13 @@ public class TimeDetectorServiceTest {
}
void resetCallTracking() {
- mLastSuggestedTime = null;
+ mLastPhoneSuggestion = null;
mLastAutoTimeDetectionToggle = null;
mDumpCalled = false;
}
- void verifySuggestTimeCalled(TimeSignal expectedSignal) {
- assertEquals(expectedSignal, mLastSuggestedTime);
+ void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
+ assertEquals(expectedSignal, mLastPhoneSuggestion);
}
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3f348a4bda8c..60290e3b785d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2049,6 +2049,10 @@ public final class Call {
return "DISCONNECTING";
case STATE_SELECT_PHONE_ACCOUNT:
return "SELECT_PHONE_ACCOUNT";
+ case STATE_SIMULATED_RINGING:
+ return "SIMULATED_RINGING";
+ case STATE_AUDIO_PROCESSING:
+ return "AUDIO_PROCESSING";
default:
Log.w(Call.class, "Unknown state %d", state);
return "UNKNOWN";
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 0983eea8e819..2ce84fbc0dc7 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -266,8 +266,13 @@ public abstract class Connection extends Conferenceable {
/**
* Speed up audio setup for MT call.
+ * <p>
+ * Used for IMS calls to indicate that mobile-terminated (incoming) call audio setup should take
+ * place as soon as the device answers the call, but prior to it being connected. This is an
+ * optimization some IMS stacks depend on to ensure prompt setup of call audio.
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
/**
@@ -304,6 +309,7 @@ public abstract class Connection extends Conferenceable {
* device.
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
/**
@@ -345,28 +351,40 @@ public abstract class Connection extends Conferenceable {
/**
* Indicates that the current device callback number should be shown.
- *
+ * <p>
+ * Supports Telephony calls where CDMA emergency callback mode is active.
* @hide
*/
+ @SystemApi
public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
/**
* Whether the call is a generic conference, where we do not know the precise state of
* participants in the conference (eg. on CDMA).
- *
+ * <p>
+ * Supports legacy telephony CDMA calls.
* @hide
*/
+ @SystemApi
public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
/**
* Connection is using high definition audio.
- * @hide
+ * <p>
+ * Indicates that the {@link Connection} is using a "high definition" audio codec. This usually
+ * implies something like AMR wideband, but the interpretation of when a call is considered high
+ * definition is left to the {@link ConnectionService} to decide.
+ * <p>
+ * Translates to {@link android.telecom.Call.Details#PROPERTY_HIGH_DEF_AUDIO}.
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
/**
* Connection is using WIFI.
- * @hide
+ * <p>
+ * Used to indicate that a call is taking place over WIFI versus a carrier network.
+ * <p>
+ * Translates to {@link android.telecom.Call.Details#PROPERTY_WIFI}.
*/
public static final int PROPERTY_WIFI = 1<<3;
@@ -393,8 +411,12 @@ public abstract class Connection extends Conferenceable {
/**
* Indicates that the connection represents a downgraded IMS conference.
+ * <p>
+ * This property is set when an IMS conference undergoes SRVCC and is re-added to Telecom as a
+ * new entity to indicate that the new connection was a conference.
* @hide
*/
+ @SystemApi
public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
/**
@@ -420,7 +442,9 @@ public abstract class Connection extends Conferenceable {
/**
* Set by the framework to indicate that the network has identified a Connection as an emergency
* call.
- * @hide
+ * <p>
+ * This is used for incoming (mobile-terminated) calls to indicate the call is from emergency
+ * services.
*/
public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1 << 10;
@@ -428,8 +452,11 @@ public abstract class Connection extends Conferenceable {
* Set by the framework to indicate that a Conference or Connection is hosted by a device other
* than the current one. Used in scenarios where the conference originator is the remote device
* and the current device is a participant of that conference.
+ * <p>
+ * This property is specific to IMS conference calls originating in Telephony.
* @hide
*/
+ @SystemApi
public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
//**********************************************************************************************
@@ -482,8 +509,12 @@ public abstract class Connection extends Conferenceable {
/**
* Boolean connection extra key on a {@link Connection} which indicates that adding an
* additional call is disallowed.
+ * <p>
+ * Used for mobile-network calls to identify scenarios where carrier requirements preclude
+ * adding another call at the current time.
* @hide
*/
+ @SystemApi
public static final String EXTRA_DISABLE_ADD_CALL =
"android.telecom.extra.DISABLE_ADD_CALL";
@@ -507,6 +538,9 @@ public abstract class Connection extends Conferenceable {
* The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the
* ID it originally referred to the connection as. Thus Telecom needs to know that the
* Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}.
+ * <p>
+ * This is an internal Telecom framework concept and is not exposed outside of the Telecom
+ * framework.
* @hide
*/
public static final String EXTRA_ORIGINAL_CONNECTION_ID =
@@ -524,7 +558,6 @@ public abstract class Connection extends Conferenceable {
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String, Bundle)}.
- * @hide
*/
public static final String EVENT_ON_HOLD_TONE_START =
"android.telecom.event.ON_HOLD_TONE_START";
@@ -533,7 +566,6 @@ public abstract class Connection extends Conferenceable {
* Connection event used to inform Telecom that it should stop the on hold tone. This is used
* to stop a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String, Bundle)}.
- * @hide
*/
public static final String EVENT_ON_HOLD_TONE_END =
"android.telecom.event.ON_HOLD_TONE_END";
@@ -564,10 +596,9 @@ public abstract class Connection extends Conferenceable {
/**
* Connection event used to inform Telecom when a hold operation on a call has failed.
- * Not intended for use by the UI at this time.
+ * <p>
* Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is
* expected to be null when this connection event is used.
- * @hide
*/
public static final String EVENT_CALL_HOLD_FAILED = "android.telecom.event.CALL_HOLD_FAILED";
@@ -577,7 +608,6 @@ public abstract class Connection extends Conferenceable {
* <p>
* Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is
* expected to be null when this connection event is used.
- * @hide
*/
public static final String EVENT_MERGE_START = "android.telecom.event.MERGE_START";
@@ -587,7 +617,6 @@ public abstract class Connection extends Conferenceable {
* <p>
* Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is
* expected to be null when this connection event is used.
- * @hide
*/
public static final String EVENT_MERGE_COMPLETE = "android.telecom.event.MERGE_COMPLETE";
@@ -599,7 +628,6 @@ public abstract class Connection extends Conferenceable {
* call is being held locally on the device. When a capable {@link ConnectionService} receives
* signalling to indicate that the remote party has put the call on hold, it can send this
* connection event.
- * @hide
*/
public static final String EVENT_CALL_REMOTELY_HELD =
"android.telecom.event.CALL_REMOTELY_HELD";
@@ -612,7 +640,6 @@ public abstract class Connection extends Conferenceable {
* call is being held locally on the device. When a capable {@link ConnectionService} receives
* signalling to indicate that the remote party has taken the call off hold, it can send this
* connection event.
- * @hide
*/
public static final String EVENT_CALL_REMOTELY_UNHELD =
"android.telecom.event.CALL_REMOTELY_UNHELD";
@@ -655,49 +682,6 @@ public abstract class Connection extends Conferenceable {
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
/**
- * Whether the given capabilities support the specified capability.
- *
- * @param capabilities A capability bit field.
- * @param capability The capability to check capabilities for.
- * @return Whether the specified capability is supported.
- * @hide
- */
- public static boolean can(int capabilities, int capability) {
- return (capabilities & capability) == capability;
- }
-
- /**
- * Whether the capabilities of this {@code Connection} supports the specified capability.
- *
- * @param capability The capability to check capabilities for.
- * @return Whether the specified capability is supported.
- * @hide
- */
- public boolean can(int capability) {
- return can(mConnectionCapabilities, capability);
- }
-
- /**
- * Removes the specified capability from the set of capabilities of this {@code Connection}.
- *
- * @param capability The capability to remove from the set.
- * @hide
- */
- public void removeCapability(int capability) {
- mConnectionCapabilities &= ~capability;
- }
-
- /**
- * Adds the specified capability to the set of capabilities of this {@code Connection}.
- *
- * @param capability The capability to add to the set.
- * @hide
- */
- public void addCapability(int capability) {
- mConnectionCapabilities |= capability;
- }
-
- /**
* Renders a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
*
* @param capabilities A capability bit field.
@@ -726,67 +710,72 @@ public abstract class Connection extends Conferenceable {
builder.append("Capabilities:");
}
- if (can(capabilities, CAPABILITY_HOLD)) {
+ if ((capabilities & CAPABILITY_HOLD) == CAPABILITY_HOLD) {
builder.append(isLong ? " CAPABILITY_HOLD" : " hld");
}
- if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
+ if ((capabilities & CAPABILITY_SUPPORT_HOLD) == CAPABILITY_SUPPORT_HOLD) {
builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld");
}
- if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
+ if ((capabilities & CAPABILITY_MERGE_CONFERENCE) == CAPABILITY_MERGE_CONFERENCE) {
builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf");
}
- if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
+ if ((capabilities & CAPABILITY_SWAP_CONFERENCE) == CAPABILITY_SWAP_CONFERENCE) {
builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf");
}
- if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
+ if ((capabilities & CAPABILITY_RESPOND_VIA_TEXT) == CAPABILITY_RESPOND_VIA_TEXT) {
builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt");
}
- if (can(capabilities, CAPABILITY_MUTE)) {
+ if ((capabilities & CAPABILITY_MUTE) == CAPABILITY_MUTE) {
builder.append(isLong ? " CAPABILITY_MUTE" : " mut");
}
- if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
+ if ((capabilities & CAPABILITY_MANAGE_CONFERENCE) == CAPABILITY_MANAGE_CONFERENCE) {
builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_LOCAL_RX) == CAPABILITY_SUPPORTS_VT_LOCAL_RX) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_LOCAL_TX) == CAPABILITY_SUPPORTS_VT_LOCAL_TX) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
+ == CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_REMOTE_RX) == CAPABILITY_SUPPORTS_VT_REMOTE_RX) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_REMOTE_TX) == CAPABILITY_SUPPORTS_VT_REMOTE_TX) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx");
}
- if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
+ if ((capabilities & CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)
+ == CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL) {
builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi");
}
- if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+ if ((capabilities & CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)
+ == CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO) {
builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a");
}
- if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
+ if ((capabilities & CAPABILITY_SPEED_UP_MT_AUDIO) == CAPABILITY_SPEED_UP_MT_AUDIO) {
builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud");
}
- if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
+ if ((capabilities & CAPABILITY_CAN_UPGRADE_TO_VIDEO) == CAPABILITY_CAN_UPGRADE_TO_VIDEO) {
builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v");
}
- if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
+ if ((capabilities & CAPABILITY_CAN_PAUSE_VIDEO) == CAPABILITY_CAN_PAUSE_VIDEO) {
builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT");
}
- if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
+ if ((capabilities & CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)
+ == CAPABILITY_CONFERENCE_HAS_NO_CHILDREN) {
builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf");
}
- if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+ if ((capabilities & CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)
+ == CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION) {
builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con");
}
- if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
+ if ((capabilities & CAPABILITY_CAN_PULL_CALL) == CAPABILITY_CAN_PULL_CALL) {
builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull");
}
- if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) {
+ if ((capabilities & CAPABILITY_SUPPORT_DEFLECT) == CAPABILITY_SUPPORT_DEFLECT) {
builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def");
}
@@ -822,43 +811,44 @@ public abstract class Connection extends Conferenceable {
builder.append("Properties:");
}
- if (can(properties, PROPERTY_SELF_MANAGED)) {
+ if ((properties & PROPERTY_SELF_MANAGED) == PROPERTY_SELF_MANAGED) {
builder.append(isLong ? " PROPERTY_SELF_MANAGED" : " self_mng");
}
- if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
+ if ((properties & PROPERTY_EMERGENCY_CALLBACK_MODE) == PROPERTY_EMERGENCY_CALLBACK_MODE) {
builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
}
- if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) {
+ if ((properties & PROPERTY_HIGH_DEF_AUDIO) == PROPERTY_HIGH_DEF_AUDIO) {
builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD");
}
- if (can(properties, PROPERTY_WIFI)) {
+ if ((properties & PROPERTY_WIFI) == PROPERTY_WIFI) {
builder.append(isLong ? " PROPERTY_WIFI" : " wifi");
}
- if (can(properties, PROPERTY_GENERIC_CONFERENCE)) {
+ if ((properties & PROPERTY_GENERIC_CONFERENCE) == PROPERTY_GENERIC_CONFERENCE) {
builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf");
}
- if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) {
+ if ((properties & PROPERTY_IS_EXTERNAL_CALL) == PROPERTY_IS_EXTERNAL_CALL) {
builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl");
}
- if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
+ if ((properties & PROPERTY_HAS_CDMA_VOICE_PRIVACY) == PROPERTY_HAS_CDMA_VOICE_PRIVACY) {
builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv");
}
- if (can(properties, PROPERTY_IS_RTT)) {
+ if ((properties & PROPERTY_IS_RTT) == PROPERTY_IS_RTT) {
builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
}
- if (can(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+ if ((properties & PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)
+ == PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL) {
builder.append(isLong ? " PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL" : " ecall");
}
- if (can(properties, PROPERTY_REMOTELY_HOSTED)) {
+ if ((properties & PROPERTY_REMOTELY_HOSTED) == PROPERTY_REMOTELY_HOSTED) {
builder.append(isLong ? " PROPERTY_REMOTELY_HOSTED" : " remote_hst");
}
@@ -888,16 +878,10 @@ public abstract class Connection extends Conferenceable {
public void onConferenceablesChanged(
Connection c, List<Conferenceable> conferenceables) {}
public void onConferenceChanged(Connection c, Conference conference) {}
- /** @hide */
- public void onConferenceParticipantsChanged(Connection c,
- List<ConferenceParticipant> participants) {}
- public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
public void onExtrasChanged(Connection c, Bundle extras) {}
public void onExtrasRemoved(Connection c, List<String> keys) {}
public void onConnectionEvent(Connection c, String event, Bundle extras) {}
- /** @hide */
- public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {}
public void onRttInitiationSuccess(Connection c) {}
public void onRttInitiationFailure(Connection c, int reason) {}
@@ -1814,11 +1798,15 @@ public abstract class Connection extends Conferenceable {
/**
* Returns the Telecom internal call ID associated with this connection. Should only be used
* for debugging and tracing purposes.
+ * <p>
+ * Note: Access to the Telecom internal call ID is used for logging purposes only; this API is
+ * provided to facilitate debugging of the Telephony stack only.
*
- * @return The Telecom call ID.
+ * @return The Telecom call ID, or {@code null} if it was not set.
* @hide
*/
- public final String getTelecomCallId() {
+ @SystemApi
+ public final @Nullable String getTelecomCallId() {
return mTelecomCallId;
}
@@ -1867,9 +1855,8 @@ public abstract class Connection extends Conferenceable {
* {@link VideoProfile#STATE_RX_ENABLED}.
*
* @return The video state of the connection.
- * @hide
*/
- public final int getVideoState() {
+ public final @VideoProfile.VideoState int getVideoState() {
return mVideoState;
}
@@ -1925,11 +1912,16 @@ public abstract class Connection extends Conferenceable {
* Retrieves the connection start time of the {@code Connnection}, if specified. A value of
* {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
* start time of the conference.
+ * <p>
+ * Note: This is an implementation detail specific to IMS conference calls over a mobile
+ * network.
*
- * @return The time at which the {@code Connnection} was connected.
+ * @return The time at which the {@code Connnection} was connected. Will be a value as retrieved
+ * from {@link System#currentTimeMillis()}.
*
* @hide
*/
+ @SystemApi
public final long getConnectTimeMillis() {
return mConnectTimeMillis;
}
@@ -1938,26 +1930,32 @@ public abstract class Connection extends Conferenceable {
* Retrieves the connection start time of the {@link Connection}, if specified. A value of
* {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
* start time of the conference.
- *
+ * <p>
* Based on the value of {@link SystemClock#elapsedRealtime()}, which ensures that wall-clock
* changes do not impact the call duration.
+ * <p>
+ * Used internally in Telephony when migrating conference participant data for IMS conferences.
*
* @return The time at which the {@link Connection} was connected.
*
* @hide
*/
+ @SystemApi
public final long getConnectElapsedTimeMillis() {
return mConnectElapsedTimeMillis;
}
/**
* Returns RIL voice radio technology used for current connection.
+ * <p>
+ * Used by the Telephony {@link ConnectionService}.
*
* @return the RIL voice radio technology used for current connection,
* see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
*
* @hide
*/
+ @SystemApi
public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
Bundle extras = getExtras();
@@ -2037,11 +2035,16 @@ public abstract class Connection extends Conferenceable {
/**
* Sets the telecom call ID associated with this Connection. The Telecom Call ID should be used
* ONLY for debugging purposes.
+ * <p>
+ * Note: Access to the Telecom internal call ID is used for logging purposes only; this API is
+ * provided to facilitate debugging of the Telephony stack only. Changing the ID via this
+ * method does NOT change any functionality in Telephony or Telecom and impacts only logging.
*
* @param callId The telecom call ID.
* @hide
*/
- public void setTelecomCallId(String callId) {
+ @SystemApi
+ public void setTelecomCallId(@NonNull String callId) {
mTelecomCallId = callId;
}
@@ -2378,12 +2381,15 @@ public abstract class Connection extends Conferenceable {
/**
* Sets the time at which a call became active on this Connection. This is set only
* when a conference call becomes active on this connection.
+ * <p>
+ * Used by telephony to maintain calls associated with an IMS Conference.
*
* @param connectTimeMillis The connection time, in milliseconds. Should be set using a value
* obtained from {@link System#currentTimeMillis()}.
*
* @hide
*/
+ @SystemApi
public final void setConnectTimeMillis(long connectTimeMillis) {
mConnectTimeMillis = connectTimeMillis;
}
@@ -2391,27 +2397,37 @@ public abstract class Connection extends Conferenceable {
/**
* Sets the time at which a call became active on this Connection. This is set only
* when a conference call becomes active on this connection.
- *
+ * <p>
+ * Used by telephony to maintain calls associated with an IMS Conference.
* @param connectElapsedTimeMillis The connection time, in milliseconds. Stored in the format
* {@link SystemClock#elapsedRealtime()}.
*
* @hide
*/
+ @SystemApi
public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
mConnectElapsedTimeMillis = connectElapsedTimeMillis;
}
/**
* Sets RIL voice radio technology used for current connection.
+ * <p>
+ * This property is set by the Telephony {@link ConnectionService}.
*
* @param vrat the RIL Voice Radio Technology used for current connection,
* see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
*
* @hide
*/
+ @SystemApi
public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
- putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
+ Bundle extras = getExtras();
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
ServiceState.rilRadioTechnologyToNetworkType(vrat));
+ putExtras(extras);
// Propagates the call radio technology to its parent {@link android.telecom.Conference}
// This action only covers non-IMS CS conference calls.
// For IMS PS call conference call, it can be updated via its host connection
@@ -2479,9 +2495,12 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Resets the CDMA connection time.
+ * <p>
+ * This is an implementation detail specific to legacy CDMA calls on mobile networks.
* @hide
- * Resets the cdma connection time.
*/
+ @SystemApi
public final void resetConnectionTime() {
for (Listener l : mListeners) {
l.onConnectionTimeReset(this);
@@ -2521,13 +2540,6 @@ public abstract class Connection extends Conferenceable {
}
/**
- * @hide
- */
- public final ConnectionService getConnectionService() {
- return mConnectionService;
- }
-
- /**
* Sets the conference that this connection is a part of. This will fail if the connection is
* already part of a conference. {@link #resetConference} to un-set the conference first.
*
@@ -2637,45 +2649,6 @@ public abstract class Connection extends Conferenceable {
}
/**
- * Adds a boolean extra to this {@code Connection}.
- *
- * @param key The extra key.
- * @param value The value.
- * @hide
- */
- public final void putExtra(String key, boolean value) {
- Bundle newExtras = new Bundle();
- newExtras.putBoolean(key, value);
- putExtras(newExtras);
- }
-
- /**
- * Adds an integer extra to this {@code Connection}.
- *
- * @param key The extra key.
- * @param value The value.
- * @hide
- */
- public final void putExtra(String key, int value) {
- Bundle newExtras = new Bundle();
- newExtras.putInt(key, value);
- putExtras(newExtras);
- }
-
- /**
- * Adds a string extra to this {@code Connection}.
- *
- * @param key The extra key.
- * @param value The value.
- * @hide
- */
- public final void putExtra(String key, String value) {
- Bundle newExtras = new Bundle();
- newExtras.putString(key, value);
- putExtras(newExtras);
- }
-
- /**
* Removes extras from this {@code Connection}.
*
* @param keys The keys of the extras to remove.
@@ -3241,53 +3214,16 @@ public abstract class Connection extends Conferenceable {
}
/**
- * Notifies listeners that the merge request failed.
- *
- * @hide
+ * Called by a {@link ConnectionService} to notify Telecom that a {@link Conference#onMerge()}
+ * request failed.
*/
- protected final void notifyConferenceMergeFailed() {
+ public final void notifyConferenceMergeFailed() {
for (Listener l : mListeners) {
l.onConferenceMergeFailed(this);
}
}
/**
- * Notifies listeners of a change to conference participant(s).
- *
- * @param conferenceParticipants The participants.
- * @hide
- */
- protected final void updateConferenceParticipants(
- List<ConferenceParticipant> conferenceParticipants) {
- for (Listener l : mListeners) {
- l.onConferenceParticipantsChanged(this, conferenceParticipants);
- }
- }
-
- /**
- * Notifies listeners that a conference call has been started.
- * @hide
- */
- protected void notifyConferenceStarted() {
- for (Listener l : mListeners) {
- l.onConferenceStarted();
- }
- }
-
- /**
- * Notifies listeners when a change has occurred to the Connection which impacts its ability to
- * be a part of a conference call.
- * @param isConferenceSupported {@code true} if the connection supports being part of a
- * conference call, {@code false} otherwise.
- * @hide
- */
- protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) {
- for (Listener l : mListeners) {
- l.onConferenceSupportedChanged(this, isConferenceSupported);
- }
- }
-
- /**
* Notifies listeners when phone account is changed. For example, when the PhoneAccount is
* changed due to an emergency call being redialed.
* @param pHandle The new PhoneAccountHandle for this connection.
@@ -3301,10 +3237,15 @@ public abstract class Connection extends Conferenceable {
/**
* Sets the {@link PhoneAccountHandle} associated with this connection.
+ * <p>
+ * Used by the Telephony {@link ConnectionService} to handle changes to the {@link PhoneAccount}
+ * which take place after call initiation (important for emergency calling scenarios).
*
+ * @param phoneAccountHandle the phone account handle to set.
* @hide
*/
- public void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+ @SystemApi
+ public void setPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
if (mPhoneAccountHandle != phoneAccountHandle) {
mPhoneAccountHandle = phoneAccountHandle;
notifyPhoneAccountChanged(phoneAccountHandle);
@@ -3313,10 +3254,16 @@ public abstract class Connection extends Conferenceable {
/**
* Returns the {@link PhoneAccountHandle} associated with this connection.
+ * <p>
+ * Used by the Telephony {@link ConnectionService} to handle changes to the {@link PhoneAccount}
+ * which take place after call initiation (important for emergency calling scenarios).
*
+ * @return the phone account handle specified via
+ * {@link #setPhoneAccountHandle(PhoneAccountHandle)}, or {@code null} if none was set.
* @hide
*/
- public PhoneAccountHandle getPhoneAccountHandle() {
+ @SystemApi
+ public @Nullable PhoneAccountHandle getPhoneAccountHandle() {
return mPhoneAccountHandle;
}
@@ -3373,9 +3320,14 @@ public abstract class Connection extends Conferenceable {
/**
* Sets the direction of this connection.
+ * <p>
+ * Used when calling {@link ConnectionService#addExistingConnection} to specify the existing
+ * call direction.
+ *
* @param callDirection The direction of this connection.
* @hide
*/
+ @SystemApi
public void setCallDirection(@Call.Details.CallDirection int callDirection) {
mCallDirection = callDirection;
}
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 2236cba498aa..2a6e8deeb13e 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -13,4 +13,5 @@ satk@google.com
shuoq@google.com
refuhoo@google.com
paulye@google.com
-nazaninb@google.com \ No newline at end of file
+nazaninb@google.com
+sarahchin@google.com \ No newline at end of file
diff --git a/telephony/java/android/telephony/CellBroadcastService.java b/telephony/java/android/telephony/CellBroadcastService.java
new file mode 100644
index 000000000000..d5e447e6c73d
--- /dev/null
+++ b/telephony/java/android/telephony/CellBroadcastService.java
@@ -0,0 +1,112 @@
+/*
+ * 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.CallSuper;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * A service which exposes the cell broadcast handling module to the system.
+ * <p>
+ * To extend this class, you must declare the service in your manifest file to require the
+ * {@link android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE} permission and include an intent
+ * filter with the {@link #CELL_BROADCAST_SERVICE_INTERFACE}.
+ * Implementations of this service should run in the phone process and with its UID.
+ * <p>
+ * For example:
+ * <pre>{@code
+ * <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ * android:sharedUserId="android.uid.phone">
+ * <service android:name=".MyCellBroadcastService"
+ * android:label="@string/service_name"
+ * android:process="com.android.phone"
+ * android:exported="true"
+ * android:permission="android.permission.BIND_CELL_BROADCAST_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.telephony.CellBroadcastService" />
+ * </intent-filter>
+ * </service>
+ * </manifest>
+ * }</pre>
+ * @hide
+ */
+@SystemApi
+public abstract class CellBroadcastService extends Service {
+
+ public static final String CELL_BROADCAST_SERVICE_INTERFACE =
+ "android.telephony.CellBroadcastService";
+
+ private final ICellBroadcastService.Stub mStubWrapper;
+
+ public CellBroadcastService() {
+ mStubWrapper = new ICellBroadcastServiceWrapper();
+ }
+
+ /**
+ * Handle a GSM cell broadcast SMS message forwarded from the system.
+ * @param slotIndex the index of the slot which received the message
+ * @param message the SMS PDU
+ */
+ public abstract void onGsmCellBroadcastSms(int slotIndex, byte[] message);
+
+ /**
+ * Handle a CDMA cell broadcast SMS message forwarded from the system.
+ * @param slotIndex the index of the slot which received the message
+ * @param message the SMS PDU
+ */
+ public abstract void onCdmaCellBroadcastSms(int slotIndex, byte[] message);
+
+ /**
+ * If overriding this method, call through to the super method for any unknown actions.
+ * {@inheritDoc}
+ */
+ @Override
+ @CallSuper
+ public IBinder onBind(Intent intent) {
+ return mStubWrapper;
+ }
+
+ /**
+ * A wrapper around ICellBroadcastService that forwards calls to implementations of
+ * {@link CellBroadcastService}.
+ * @hide
+ */
+ public class ICellBroadcastServiceWrapper extends ICellBroadcastService.Stub {
+ /**
+ * Handle a GSM cell broadcast SMS.
+ * @param slotIndex the index of the slot which received the broadcast
+ * @param message the SMS message PDU
+ */
+ @Override
+ public void handleGsmCellBroadcastSms(int slotIndex, byte[] message) {
+ CellBroadcastService.this.onGsmCellBroadcastSms(slotIndex, message);
+ }
+
+ /**
+ * Handle a CDMA cell broadcast SMS.
+ * @param slotIndex the index of the slot which received the broadcast
+ * @param message the SMS message PDU
+ */
+ @Override
+ public void handleCdmaCellBroadcastSms(int slotIndex, byte[] message) {
+ CellBroadcastService.this.onCdmaCellBroadcastSms(slotIndex, message);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 258a873c3ac5..b7dab161c331 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.CallSuper;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,6 +35,15 @@ public abstract class CellIdentity implements Parcelable {
/** @hide */
public static final int INVALID_CHANNEL_NUMBER = -1;
+ /**
+ * parameters for validation
+ * @hide
+ */
+ public static final int MCC_LENGTH = 3;
+
+ private static final int MNC_MIN_LENGTH = 2;
+ private static final int MNC_MAX_LENGTH = 3;
+
// Log tag
/** @hide */
protected final String mTag;
@@ -61,7 +71,7 @@ public abstract class CellIdentity implements Parcelable {
mType = type;
// Only allow INT_MAX if unknown string mcc/mnc
- if (mcc == null || mcc.matches("^[0-9]{3}$")) {
+ if (mcc == null || isMcc(mcc)) {
mMccStr = mcc;
} else if (mcc.isEmpty() || mcc.equals(String.valueOf(Integer.MAX_VALUE))) {
// If the mccStr is empty or unknown, set it as null.
@@ -73,7 +83,7 @@ public abstract class CellIdentity implements Parcelable {
log("invalid MCC format: " + mcc);
}
- if (mnc == null || mnc.matches("^[0-9]{2,3}$")) {
+ if (mnc == null || isMnc(mnc)) {
mMncStr = mnc;
} else if (mnc.isEmpty() || mnc.equals(String.valueOf(Integer.MAX_VALUE))) {
// If the mncStr is empty or unknown, set it as null.
@@ -206,6 +216,17 @@ public abstract class CellIdentity implements Parcelable {
dest.writeString(mAlphaShort);
}
+ /** Used by phone interface manager to verify if a given string is valid MccMnc
+ * @hide
+ */
+ public static boolean isValidPlmn(@NonNull String plmn) {
+ if (plmn.length() < MCC_LENGTH + MNC_MIN_LENGTH
+ || plmn.length() > MCC_LENGTH + MNC_MAX_LENGTH) {
+ return false;
+ }
+ return (isMcc(plmn.substring(0, MCC_LENGTH)) && isMnc(plmn.substring(MCC_LENGTH)));
+ }
+
/**
* Construct from Parcel
* @hide
@@ -262,4 +283,31 @@ public abstract class CellIdentity implements Parcelable {
if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
return value;
}
+
+ /** @hide */
+ private static boolean isMcc(@NonNull String mcc) {
+ // ensure no out of bounds indexing
+ if (mcc.length() != MCC_LENGTH) return false;
+
+ // Character.isDigit allows all unicode digits, not just [0-9]
+ for (int i = 0; i < MCC_LENGTH; i++) {
+ if (mcc.charAt(i) < '0' || mcc.charAt(i) > '9') return false;
+ }
+
+ return true;
+ }
+
+ /** @hide */
+ private static boolean isMnc(@NonNull String mnc) {
+ // ensure no out of bounds indexing
+ if (mnc.length() < MNC_MIN_LENGTH || mnc.length() > MNC_MAX_LENGTH) return false;
+
+ // Character.isDigit allows all unicode digits, not just [0-9]
+ for (int i = 0; i < mnc.length(); i++) {
+ if (mnc.charAt(i) < '0' || mnc.charAt(i) > '9') return false;
+ }
+
+ return true;
+ }
+
}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index cdf4c935f84b..aa7e21a82500 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -340,6 +340,19 @@ public final class DisconnectCause {
*/
public static final int MEDIA_TIMEOUT = 77;
+ /**
+ * Indicates that an emergency call cannot be placed over WFC because the service is not
+ * available in the current location.
+ * @hide
+ */
+ public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78;
+
+ /**
+ * Indicates that WiFi calling service is not available in the current location.
+ * @hide
+ */
+ public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -510,6 +523,10 @@ public final class DisconnectCause {
return "OTASP_PROVISIONING_IN_PROCESS";
case MEDIA_TIMEOUT:
return "MEDIA_TIMEOUT";
+ case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+ return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
+ case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+ return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/ICellBroadcastService.aidl b/telephony/java/android/telephony/ICellBroadcastService.aidl
new file mode 100644
index 000000000000..eff64a2e35ba
--- /dev/null
+++ b/telephony/java/android/telephony/ICellBroadcastService.aidl
@@ -0,0 +1,32 @@
+/**
+ * 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;
+
+/**
+ * Service bound to by the system to allow custom handling of cell broadcast messages.
+ * <p>
+ * @see android.telephony.CellBroadcastService
+ * @hide
+ */
+interface ICellBroadcastService {
+
+ /** @see android.telephony.CellBroadcastService#onGsmCellBroadcastSms */
+ oneway void handleGsmCellBroadcastSms(int slotId, in byte[] message);
+
+ /** @see android.telephony.CellBroadcastService#onCdmaCellBroadcastSms */
+ oneway void handleCdmaCellBroadcastSms(int slotId, in byte[] message);
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 42d65e2bbce6..1aac9196efff 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6756,6 +6756,40 @@ public class TelephonyManager {
}
/**
+ * Replace the contents of the forbidden PLMN SIM file with the provided values.
+ * Passing an empty list will clear the contents of the EFfplmn file.
+ * If the provided list is shorter than the size of EFfplmn, then the list will be padded
+ * up to the file size with 'FFFFFF'. (required by 3GPP TS 31.102 spec 4.2.16)
+ * If the list is longer than the size of EFfplmn, then the file will be written from the
+ * beginning of the list up to the file size.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param fplmns a list of PLMNs to be forbidden.
+ *
+ * @return number of PLMNs that were successfully written to the SIM FPLMN list.
+ * This may be less than the number of PLMNs passed in where the SIM file does not have enough
+ * room for all of the values passed in. Return -1 in the event of an unexpected failure
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public int setForbiddenPlmns(@NonNull List<String> fplmns) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return 0;
+ return telephony.setForbiddenPlmns(
+ getSubId(), APPTYPE_USIM, fplmns, getOpPackageName());
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage());
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ Rlog.e(TAG, "setForbiddenPlmns NullPointerException: " + ex.getMessage());
+ }
+ return 0;
+ }
+
+ /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 036a7b329d77..1e0d9a786acc 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -872,6 +872,19 @@ public final class ImsReasonInfo implements Parcelable {
*/
public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
+ /**
+ * An attempt was made to place an emergency call over WFC when emergency services is not
+ * currently available in the current location.
+ * @hide
+ */
+ public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622;
+
+ /**
+ * Indicates that WiFi calling service is not available in the current location.
+ * @hide
+ */
+ public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623;
+
/*
* OEM specific error codes. To be used by OEMs when they don't want to reveal error code which
* would be replaced by ERROR_UNSPECIFIED.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 919a0b08e11f..e4674f145979 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1603,6 +1603,18 @@ interface ITelephony {
String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
/**
+ * Set the forbidden PLMN list from the givven app type (ex APPTYPE_USIM) on a particular
+ * subscription.
+ *
+ * @param subId subId the id of the subscription
+ * @param appType appType the uicc app type, must be USIM or SIM.
+ * @param fplmns plmns the Forbiden plmns list that needed to be written to the SIM.
+ * @param content callingPackage the op Package name.
+ * @return number of fplmns that is successfully written to the SIM
+ */
+ int setForbiddenPlmns(int subId, int appType, in List<String> fplmns, String callingPackage);
+
+ /**
* Check if phone is in emergency callback mode
* @return true if phone is in emergency callback mode
* @param subId the subscription ID that this action applies to.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index 6eea118787a7..c65c45fa015b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -461,7 +461,11 @@ public class GsmSmsCbMessage {
}
}
- static final class GeoFencingTriggerMessage {
+ /**
+ * Part of a GSM SMS cell broadcast message which may trigger geo-fencing logic.
+ * @hide
+ */
+ public static final class GeoFencingTriggerMessage {
/**
* Indicate the list of active alerts share their warning area coordinates which means the
* broadcast area is the union of the broadcast areas of the active alerts in this list.
@@ -476,6 +480,11 @@ public class GsmSmsCbMessage {
this.cbIdentifiers = cbIdentifiers;
}
+ /**
+ * Whether the trigger message indicates that the broadcast areas are shared between all
+ * active alerts.
+ * @return true if broadcast areas are to be shared
+ */
boolean shouldShareBroadcastArea() {
return type == TYPE_ACTIVE_ALERT_SHARE_WAC;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
index acdc83867d2f..465840f3bc7f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
@@ -72,22 +72,22 @@ public class SmsCbHeader {
/**
* Length of SMS-CB header
*/
- static final int PDU_HEADER_LENGTH = 6;
+ public static final int PDU_HEADER_LENGTH = 6;
/**
* GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
*/
- static final int FORMAT_GSM = 1;
+ public static final int FORMAT_GSM = 1;
/**
* UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
*/
- static final int FORMAT_UMTS = 2;
+ public static final int FORMAT_UMTS = 2;
/**
- * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3
+ * ETWS pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3
*/
- static final int FORMAT_ETWS_PRIMARY = 3;
+ public static final int FORMAT_ETWS_PRIMARY = 3;
/**
* Message type value as defined in 3gpp TS 25.324, section 11.1.
@@ -237,11 +237,11 @@ public class SmsCbHeader {
return mMessageIdentifier;
}
- int getDataCodingScheme() {
+ public int getDataCodingScheme() {
return mDataCodingScheme;
}
- DataCodingScheme getDataCodingSchemeStructedData() {
+ public DataCodingScheme getDataCodingSchemeStructedData() {
return mDataCodingSchemeStructedData;
}
@@ -253,11 +253,11 @@ public class SmsCbHeader {
return mNrOfPages;
}
- SmsCbEtwsInfo getEtwsInfo() {
+ public SmsCbEtwsInfo getEtwsInfo() {
return mEtwsInfo;
}
- SmsCbCmasInfo getCmasInfo() {
+ public SmsCbCmasInfo getCmasInfo() {
return mCmasInfo;
}
@@ -265,7 +265,7 @@ public class SmsCbHeader {
* Return whether this broadcast is an emergency (PWS) message type.
* @return true if this message is emergency type; false otherwise
*/
- boolean isEmergencyMessage() {
+ public boolean isEmergencyMessage() {
return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER
&& mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER;
}
@@ -283,7 +283,7 @@ public class SmsCbHeader {
* Return whether this broadcast is an ETWS primary notification.
* @return true if this message is an ETWS primary notification; false otherwise
*/
- boolean isEtwsPrimaryNotification() {
+ public boolean isEtwsPrimaryNotification() {
return mFormat == FORMAT_ETWS_PRIMARY;
}
@@ -291,7 +291,7 @@ public class SmsCbHeader {
* Return whether this broadcast is in UMTS format.
* @return true if this message is in UMTS format; false otherwise
*/
- boolean isUmtsFormat() {
+ public boolean isUmtsFormat() {
return mFormat == FORMAT_UMTS;
}
@@ -583,4 +583,4 @@ public class SmsCbHeader {
this.hasLanguageIndicator = hasLanguageIndicator;
}
}
-} \ No newline at end of file
+}
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 6b3df94063bf..96e215cf6f45 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -22,9 +22,11 @@ import android.graphics.Bitmap;
import android.graphics.Color;
import android.telephony.Rlog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet;
import java.io.UnsupportedEncodingException;
+import java.util.List;
/**
* Various methods, useful for dealing with SIM data.
@@ -32,6 +34,11 @@ import java.io.UnsupportedEncodingException;
public class IccUtils {
static final String LOG_TAG="IccUtils";
+ // 3GPP specification constants
+ // Spec reference TS 31.102 section 4.2.16
+ @VisibleForTesting
+ static final int FPLMN_BYTE_SIZE = 3;
+
// A table mapping from a number to a hex character for fast encoding hex strings.
private static final char[] HEX_CHARS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
@@ -883,4 +890,27 @@ public class IccUtils {
}
return 0;
}
+
+ /**
+ * Encode the Fplmns into byte array to write to EF.
+ *
+ * @param fplmns Array of fplmns to be serialized.
+ * @param dataLength the size of the EF file.
+ * @return the encoded byte array in the correct format for FPLMN file.
+ */
+ public static byte[] encodeFplmns(List<String> fplmns, int dataLength) {
+ byte[] serializedFplmns = new byte[dataLength];
+ int offset = 0;
+ for (String fplmn : fplmns) {
+ if (offset >= dataLength) break;
+ stringToBcdPlmn(fplmn, serializedFplmns, offset);
+ offset += FPLMN_BYTE_SIZE;
+ }
+ //pads to the length of the EF file.
+ while (offset < dataLength) {
+ // required by 3GPP TS 31.102 spec 4.2.16
+ serializedFplmns[offset++] = (byte) 0xff;
+ }
+ return serializedFplmns;
+ }
}
diff --git a/tests/BootImageProfileTest/AndroidTest.xml b/tests/BootImageProfileTest/AndroidTest.xml
index c13200778c4b..b4f2663585cc 100644
--- a/tests/BootImageProfileTest/AndroidTest.xml
+++ b/tests/BootImageProfileTest/AndroidTest.xml
@@ -22,8 +22,8 @@
<!-- we need this magic flag, otherwise it always reboots and breaks the selinux -->
<option name="force-skip-system-props" value="true" />
- <option name="run-command" value="setprop dalvik.vm.profilesystemserver true" />
- <option name="run-command" value="setprop dalvik.vm.profilebootclasspath true" />
+ <option name="run-command" value="device_config put runtime_native_boot profilesystemserver true" />
+ <option name="run-command" value="device_config put runtime_native_boot profilebootclasspath true" />
<!-- Profiling does not pick up the above changes we restart the shell -->
<option name="run-command" value="stop" />
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index fe1d9d26c7e7..81937e6b7005 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -46,17 +46,23 @@ public class BootImageProfileTest implements IDeviceTest {
*/
@Test
public void testProperties() throws Exception {
- String res = mTestDevice.getProperty("dalvik.vm.profilebootclasspath");
+ String res = mTestDevice.getProperty(
+ "persist.device_config.runtime_native_boot.profilebootclasspath");
assertTrue("profile boot class path not enabled", res != null && res.equals("true"));
- res = mTestDevice.getProperty("dalvik.vm.profilesystemserver");
+ res = mTestDevice.getProperty(
+ "persist.device_config.runtime_native_boot.profilesystemserver");
assertTrue("profile system server not enabled", res != null && res.equals("true"));
}
- private void forceSaveProfile(String pkg) throws Exception {
+ private boolean forceSaveProfile(String pkg) throws Exception {
String pid = mTestDevice.executeShellCommand("pidof " + pkg).trim();
- assertTrue("Invalid pid " + pid, pid.length() > 0);
+ if (pid.length() == 0) {
+ // Not yet running.
+ return false;
+ }
String res = mTestDevice.executeShellCommand("kill -s SIGUSR1 " + pid).trim();
assertTrue("kill SIGUSR1: " + res, res.length() == 0);
+ return true;
}
@Test
@@ -69,10 +75,13 @@ public class BootImageProfileTest implements IDeviceTest {
// Wait up to 20 seconds for the profile to be saved.
for (int i = 0; i < 20; ++i) {
// Force save the profile since we truncated it.
- forceSaveProfile("system_server");
- String s = mTestDevice.executeShellCommand("wc -c <" + SYSTEM_SERVER_PROFILE).trim();
- if (!"0".equals(s)) {
- break;
+ if (forceSaveProfile("system_server")) {
+ // Might fail if system server is not yet running.
+ String s = mTestDevice.executeShellCommand(
+ "wc -c <" + SYSTEM_SERVER_PROFILE).trim();
+ if (!"0".equals(s)) {
+ break;
+ }
}
Thread.sleep(1000);
}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index e91abb6c4a44..b9b2238572ac 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -5,7 +5,6 @@ java_defaults {
name: "FrameworksNetTests-jni-defaults",
jni_libs: [
"ld-android",
- "libartbase",
"libbacktrace",
"libbase",
"libbinder",
@@ -16,7 +15,6 @@ java_defaults {
"libcgrouprc",
"libcrypto",
"libcutils",
- "libdexfile",
"libdl_android",
"libhidl-gen-utils",
"libhidlbase",
@@ -46,7 +44,11 @@ java_defaults {
android_test {
name: "FrameworksNetTests",
defaults: ["FrameworksNetTests-jni-defaults"],
- srcs: ["java/**/*.java", "java/**/*.kt"],
+ srcs: [
+ ":tethering-tests-src",
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 2ca0d1a81e13..15691127cab7 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -271,7 +271,7 @@ public class NetworkCapabilitiesTest {
.addCapability(NET_CAPABILITY_NOT_METERED);
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 11);
+ assertParcelSane(netCap, 12);
}
@Test
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 05912e85426a..b6ccebb3dcd3 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -19,11 +19,13 @@ package android.net.ip;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHERING_WIFI_P2P;
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.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.ip.IpServer.STATE_AVAILABLE;
+import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
import static android.net.ip.IpServer.STATE_TETHERED;
import static android.net.ip.IpServer.STATE_UNAVAILABLE;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
@@ -256,6 +258,23 @@ public class IpServerTest {
}
@Test
+ public void canBeTetheredAsWifiP2p() throws Exception {
+ initStateMachine(TETHERING_WIFI_P2P);
+
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
+ InOrder inOrder = inOrder(mCallback, mNMService);
+ inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
+ inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
+ inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(
+ eq(mIpServer), mLinkPropertiesCaptor.capture());
+ assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
+ verifyNoMoreInteractions(mNMService, mStatsService, mCallback);
+ }
+
+ @Test
public void handlesFirstUpstreamChange() throws Exception {
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
@@ -419,6 +438,14 @@ public class IpServerTest {
}
@Test
+ public void startsDhcpServerOnWifiP2p() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI_P2P, UPSTREAM_IFACE);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+
+ assertDhcpStarted(new IpPrefix("192.168.49.0/24"));
+ }
+
+ @Test
public void doesNotStartDhcpServerIfDisabled() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 46e27c1d3d3b..1f2bb0ac05ee 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.Instrumentation;
import android.content.Context;
@@ -283,6 +284,107 @@ public class InetDiagSocketTest {
assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
}
+ // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
+ private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0100" + // flags = NLM_F_REQUEST
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "02" + // family = AF_INET
+ "06" + // protcol = IPPROTO_TCP
+ "02" + // idiag_ext = INET_DIAG_INFO
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "3039" + // idiag_sport = 12345
+ "d431" + // idiag_dport = 54321
+ "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
+ "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
+ "00000000" + // idiag_if
+ "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+
+ private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
+ private static final int TCP_ALL_STATES = 0xffffffff;
+ @Test
+ public void testInetDiagReqV2TcpInetWithExt() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(
+ InetAddress.getByName("1.2.3.4"), 12345);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
+ 54321);
+ byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
+ NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
+
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
+
+ local = new InetSocketAddress(
+ InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
+ remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+ 47473);
+ msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
+ NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
+ }
+
+ // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
+ private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
+ // struct nlmsghdr
+ "48000000" + // length = 72
+ "1400" + // type = SOCK_DIAG_BY_FAMILY
+ "0100" + // flags = NLM_F_REQUEST
+ "00000000" + // seqno
+ "00000000" + // pid (0 == kernel)
+ // struct inet_diag_req_v2
+ "0a" + // family = AF_INET6
+ "06" + // protcol = IPPROTO_TCP
+ "00" + // idiag_ext
+ "00" + // pad
+ "ffffffff" + // idiag_states
+ // inet_diag_sockid
+ "0000" + // idiag_sport
+ "0000" + // idiag_dport
+ "00000000000000000000000000000000" + // idiag_src
+ "00000000000000000000000000000000" + // idiag_dst
+ "00000000" + // idiag_if
+ "0000000000000000"; // idiag_cookie
+
+ private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
+ HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
+
+ @Test
+ public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
+ InetSocketAddress local = new InetSocketAddress(
+ InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
+ InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
+ 54321);
+ // Verify no socket specified if either local or remote socket address is null.
+ byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
+ NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+ byte[] msg;
+ try {
+ msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
+ NLM_F_REQUEST);
+ fail("Both remote and local should be null, expected UnknownHostException");
+ } catch (NullPointerException e) {
+ }
+
+ try {
+ msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
+ NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+ fail("Both remote and local should be null, expected UnknownHostException");
+ } catch (NullPointerException e) {
+ }
+
+ msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
+ NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
+ assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
+ }
+
// Hexadecimal representation of InetDiagReqV2 request.
private static final String INET_DIAG_MSG_HEX =
// struct nlmsghdr
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index cf3fba8bef91..61f37fd6c7e2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -33,6 +33,7 @@ import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
@@ -492,6 +493,8 @@ public class ConnectivityServiceTest {
private INetworkMonitor mNetworkMonitor;
private INetworkMonitorCallbacks mNmCallbacks;
private int mNmValidationResult = VALIDATION_RESULT_BASE;
+ private int mProbesCompleted;
+ private int mProbesSucceeded;
private String mNmValidationRedirectUrl = null;
private boolean mNmProvNotificationRequested = false;
@@ -559,6 +562,7 @@ public class ConnectivityServiceTest {
mNmProvNotificationRequested = false;
}
+ mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
mNmCallbacks.notifyNetworkTested(
mNmValidationResult, mNmValidationRedirectUrl);
@@ -581,7 +585,7 @@ public class ConnectivityServiceTest {
* @param validated Indicate if network should pretend to be validated.
*/
public void connect(boolean validated) {
- connect(validated, true);
+ connect(validated, true, false /* isStrictMode */);
}
/**
@@ -589,13 +593,13 @@ public class ConnectivityServiceTest {
* @param validated Indicate if network should pretend to be validated.
* @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
*/
- public void connect(boolean validated, boolean hasInternet) {
+ public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
ConnectivityManager.NetworkCallback callback = null;
final ConditionVariable validatedCv = new ConditionVariable();
if (validated) {
- setNetworkValid();
+ setNetworkValid(isStrictMode);
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(getNetworkCapabilities().getTransportTypes()[0])
.clearCapabilities()
@@ -620,15 +624,15 @@ public class ConnectivityServiceTest {
if (validated) {
// Wait for network to validate.
waitFor(validatedCv);
- setNetworkInvalid();
+ setNetworkInvalid(isStrictMode);
}
if (callback != null) mCm.unregisterNetworkCallback(callback);
}
- public void connectWithCaptivePortal(String redirectUrl) {
- setNetworkPortal(redirectUrl);
- connect(false);
+ public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) {
+ setNetworkPortal(redirectUrl, isStrictMode);
+ connect(false, true /* hasInternet */, isStrictMode);
}
public void connectWithPartialConnectivity() {
@@ -636,34 +640,75 @@ public class ConnectivityServiceTest {
connect(false);
}
- public void connectWithPartialValidConnectivity() {
- setNetworkPartialValid();
- connect(false);
+ public void connectWithPartialValidConnectivity(boolean isStrictMode) {
+ setNetworkPartialValid(isStrictMode);
+ connect(false, true /* hasInternet */, isStrictMode);
}
- void setNetworkValid() {
+ void setNetworkValid(boolean isStrictMode) {
mNmValidationResult = VALIDATION_RESULT_VALID;
mNmValidationRedirectUrl = null;
+ int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTP;
+ if (isStrictMode) {
+ probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+ }
+ // The probesCompleted equals to probesSucceeded for the case of valid network, so put
+ // the same value into two different parameter of the method.
+ setProbesStatus(probesSucceeded, probesSucceeded);
}
- void setNetworkInvalid() {
+ void setNetworkInvalid(boolean isStrictMode) {
mNmValidationResult = VALIDATION_RESULT_INVALID;
mNmValidationRedirectUrl = null;
+ int probesCompleted = VALIDATION_RESULT_BASE;
+ int probesSucceeded = VALIDATION_RESULT_INVALID;
+ // If the isStrictMode is true, it means the network is invalid when NetworkMonitor
+ // tried to validate the private DNS but failed.
+ if (isStrictMode) {
+ probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP;
+ probesSucceeded = probesCompleted;
+ probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+ }
+ setProbesStatus(probesCompleted, probesSucceeded);
}
- void setNetworkPortal(String redirectUrl) {
- setNetworkInvalid();
+ void setNetworkPortal(String redirectUrl, boolean isStrictMode) {
+ setNetworkInvalid(isStrictMode);
mNmValidationRedirectUrl = redirectUrl;
+ // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
+ // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
+ int probesCompleted = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ int probesSucceeded = VALIDATION_RESULT_INVALID;
+ if (isStrictMode) {
+ probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+ }
+ setProbesStatus(probesCompleted, probesSucceeded);
}
void setNetworkPartial() {
mNmValidationResult = VALIDATION_RESULT_PARTIAL;
mNmValidationRedirectUrl = null;
+ int probesCompleted = VALIDATION_RESULT_BASE;
+ int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ setProbesStatus(probesCompleted, probesSucceeded);
}
- void setNetworkPartialValid() {
- mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
- mNmValidationRedirectUrl = null;
+ void setNetworkPartialValid(boolean isStrictMode) {
+ setNetworkPartial();
+ mNmValidationResult |= VALIDATION_RESULT_VALID;
+ int probesCompleted = VALIDATION_RESULT_BASE;
+ int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+ // Suppose the partial network cannot pass the private DNS validation as well, so only
+ // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
+ if (isStrictMode) {
+ probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+ }
+ setProbesStatus(probesCompleted, probesSucceeded);
+ }
+
+ void setProbesStatus(int probesCompleted, int probesSucceeded) {
+ mProbesCompleted = probesCompleted;
+ mProbesSucceeded = probesSucceeded;
}
public String waitForRedirectUrl() {
@@ -2226,7 +2271,7 @@ public class ConnectivityServiceTest {
// With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
// probe.
- mWiFiNetworkAgent.setNetworkPartialValid();
+ mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
// If the user chooses yes to use this partial connectivity wifi, switch the default
// network to wifi and check if wifi becomes valid or not.
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
@@ -2299,7 +2344,7 @@ public class ConnectivityServiceTest {
callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
- mWiFiNetworkAgent.setNetworkValid();
+ mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
// validated.
@@ -2317,7 +2362,7 @@ public class ConnectivityServiceTest {
// NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
// valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
// notifyNetworkConnected.
- mWiFiNetworkAgent.connectWithPartialValidConnectivity();
+ mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
@@ -2343,7 +2388,7 @@ public class ConnectivityServiceTest {
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String redirectUrl = "http://android.com/path";
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl);
+ mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
@@ -2361,7 +2406,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent);
// Report partial connectivity is accepted.
- mWiFiNetworkAgent.setNetworkPartialValid();
+ mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
false /* always */);
waitForIdle();
@@ -2392,7 +2437,7 @@ public class ConnectivityServiceTest {
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
+ mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
@@ -2405,13 +2450,13 @@ public class ConnectivityServiceTest {
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
+ mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent.setNetworkValid();
+ mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -2423,7 +2468,7 @@ public class ConnectivityServiceTest {
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
- mWiFiNetworkAgent.setNetworkInvalid();
+ mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
}
@@ -2454,7 +2499,7 @@ public class ConnectivityServiceTest {
mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
// Turn into a captive portal.
- mWiFiNetworkAgent.setNetworkPortal("http://example.com");
+ mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */);
mCm.reportNetworkConnectivity(wifiNetwork, false);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -2475,7 +2520,7 @@ public class ConnectivityServiceTest {
assertEquals(testValue, signInIntent.getStringExtra(testKey));
// Report that the captive portal is dismissed, and check that callbacks are fired
- mWiFiNetworkAgent.setNetworkValid();
+ mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -2504,7 +2549,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
+ mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
mWiFiNetworkAgent.expectDisconnected();
mWiFiNetworkAgent.expectPreventReconnectReceived();
@@ -3219,7 +3264,7 @@ public class ConnectivityServiceTest {
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi.
- mWiFiNetworkAgent.setNetworkInvalid();
+ mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -3263,7 +3308,7 @@ public class ConnectivityServiceTest {
wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi and expect the dialog to appear.
- mWiFiNetworkAgent.setNetworkInvalid();
+ mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -4299,7 +4344,7 @@ public class ConnectivityServiceTest {
mCm.registerNetworkCallback(request, callback);
// Bring up wifi aware network.
- wifiAware.connect(false, false);
+ wifiAware.connect(false, false, false /* isStrictMode */);
callback.expectAvailableCallbacksUnvalidated(wifiAware);
assertNull(mCm.getActiveNetworkInfo());
@@ -4537,6 +4582,44 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testPrivateDnsNotification() throws Exception {
+ NetworkRequest request = new NetworkRequest.Builder()
+ .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+ // Bring up wifi.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ // Private DNS resolution failed, checking if the notification will be shown or not.
+ mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+ mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ waitForIdle();
+ // If network validation failed, NetworkMonitor will re-evaluate the network.
+ // ConnectivityService should filter the redundant notification. This part is trying to
+ // simulate that situation and check if ConnectivityService could filter that case.
+ mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ waitForIdle();
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notifyAsUser(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+ // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
+ // shown.
+ mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
+ mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ waitForIdle();
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancelAsUser(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), eq(UserHandle.ALL));
+ // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
+ // shown again.
+ mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+ mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ waitForIdle();
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notifyAsUser(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+ }
+
+ @Test
public void testPrivateDnsSettingsChange() throws Exception {
// Clear any interactions that occur as a result of CS starting up.
reset(mMockDnsResolver);
@@ -4793,7 +4876,7 @@ public class ConnectivityServiceTest {
// by NetworkMonitor
assertFalse(NetworkMonitorUtils.isValidationRequired(
vpnNetworkAgent.getNetworkCapabilities()));
- vpnNetworkAgent.setNetworkValid();
+ vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
vpnNetworkAgent.connect(false);
mMockVpn.connect();
@@ -4882,7 +4965,8 @@ public class ConnectivityServiceTest {
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ false /* isStrictMode */);
mMockVpn.connect();
defaultCallback.assertNoCallback();
@@ -4913,7 +4997,8 @@ public class ConnectivityServiceTest {
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
+ vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */,
+ false /* isStrictMode */);
mMockVpn.connect();
defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
@@ -4945,7 +5030,8 @@ public class ConnectivityServiceTest {
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+ vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */,
+ false /* isStrictMode */);
mMockVpn.connect();
// Even though the VPN is unvalidated, it becomes the default network for our app.
@@ -4968,7 +5054,7 @@ public class ConnectivityServiceTest {
vpnNetworkAgent.getNetworkCapabilities()));
// Pretend that the VPN network validates.
- vpnNetworkAgent.setNetworkValid();
+ vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
vpnNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
// Expect to see the validated capability, but no other changes, because the VPN is already
// the default network for the app.
@@ -5000,7 +5086,8 @@ public class ConnectivityServiceTest {
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.connect();
mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ false /* isStrictMode */);
vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
@@ -5099,7 +5186,8 @@ public class ConnectivityServiceTest {
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.connect();
mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ false /* isStrictMode */);
vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index c030c3e9ac86..5f62c08f55f3 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -25,8 +25,10 @@ import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -90,6 +92,9 @@ import android.net.util.NetworkConstants;
import android.net.util.SharedLog;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -140,6 +145,7 @@ public class TetheringTest {
private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0";
+ private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@@ -216,9 +222,10 @@ public class TetheringTest {
assertTrue("Non-mocked interface " + ifName,
ifName.equals(TEST_USB_IFNAME)
|| ifName.equals(TEST_WLAN_IFNAME)
- || ifName.equals(TEST_MOBILE_IFNAME));
+ || ifName.equals(TEST_MOBILE_IFNAME)
+ || ifName.equals(TEST_P2P_IFNAME));
final String[] ifaces = new String[] {
- TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME };
+ TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
}
@@ -361,6 +368,8 @@ public class TetheringTest {
.thenReturn(new String[] { "test_rndis\\d" });
when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
.thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
+ .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
@@ -369,7 +378,7 @@ public class TetheringTest {
.thenReturn(false);
when(mNMService.listInterfaces())
.thenReturn(new String[] {
- TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME});
+ TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
when(mNMService.getInterfaceConfig(anyString()))
.thenReturn(new InterfaceConfiguration());
when(mRouterAdvertisementDaemon.start())
@@ -423,6 +432,31 @@ public class TetheringTest {
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private static final String[] P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST = {
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_WIFI_STATE
+ };
+
+ private void sendWifiP2pConnectionChanged(
+ boolean isGroupFormed, boolean isGroupOwner, String ifname) {
+ WifiP2pInfo p2pInfo = new WifiP2pInfo();
+ p2pInfo.groupFormed = isGroupFormed;
+ p2pInfo.isGroupOwner = isGroupOwner;
+
+ NetworkInfo networkInfo = new NetworkInfo(TYPE_WIFI_P2P, 0, null, null);
+
+ WifiP2pGroup group = new WifiP2pGroup();
+ group.setIsGroupOwner(isGroupOwner);
+ group.setInterface(ifname);
+
+ final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
+ intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, networkInfo);
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
+ mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
+ P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
+ }
+
private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.putExtra(USB_CONNECTED, connected);
@@ -436,11 +470,11 @@ public class TetheringTest {
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void verifyInterfaceServingModeStarted() throws Exception {
- verify(mNMService, times(1)).getInterfaceConfig(TEST_WLAN_IFNAME);
+ private void verifyInterfaceServingModeStarted(String ifname) throws Exception {
+ verify(mNMService, times(1)).getInterfaceConfig(ifname);
verify(mNMService, times(1))
- .setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
+ .setInterfaceConfig(eq(ifname), any(InterfaceConfiguration.class));
+ verify(mNMService, times(1)).tetherInterface(ifname);
}
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
@@ -530,7 +564,7 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY);
mLooper.dispatchAll();
- verifyInterfaceServingModeStarted();
+ verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
@@ -542,8 +576,9 @@ public class TetheringTest {
verifyNoMoreInteractions(mWifiManager);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
- // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+ // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+ // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+ assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
@@ -552,9 +587,9 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // TODO: Why is {g,s}etInterfaceConfig() called more than once?
- verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
- verify(mNMService, atLeastOnce())
+ // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
+ verify(mNMService, times(2)).getInterfaceConfig(TEST_WLAN_IFNAME);
+ verify(mNMService, times(2))
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
@@ -770,7 +805,7 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
- verifyInterfaceServingModeStarted();
+ verifyInterfaceServingModeStarted(TEST_WLAN_IFNAME);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
@@ -785,8 +820,9 @@ public class TetheringTest {
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
- // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+ // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+ // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+ assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
/////
// We do not currently emulate any upstream being found.
@@ -809,7 +845,7 @@ public class TetheringTest {
mLooper.dispatchAll();
verify(mNMService, times(1)).untetherInterface(TEST_WLAN_IFNAME);
- // TODO: Why is {g,s}etInterfaceConfig() called more than once?
+ // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
verify(mNMService, atLeastOnce()).getInterfaceConfig(TEST_WLAN_IFNAME);
verify(mNMService, atLeastOnce())
.setInterfaceConfig(eq(TEST_WLAN_IFNAME), any(InterfaceConfiguration.class));
@@ -857,8 +893,9 @@ public class TetheringTest {
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
- // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+ // There are 3 state change event:
+ // AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE.
+ assertEquals(3, mTetheringDependencies.isTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
verify(mNMService, times(1)).setIpForwardingEnabled(true);
@@ -1031,6 +1068,133 @@ public class TetheringTest {
assertEquals(fakeSubId, newConfig.subId);
}
+ private void workingWifiP2pGroupOwner(
+ boolean emulateInterfaceStatusChanged) throws Exception {
+ if (emulateInterfaceStatusChanged) {
+ mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+ }
+ sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
+ mLooper.dispatchAll();
+
+ verifyInterfaceServingModeStarted(TEST_P2P_IFNAME);
+ verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_AVAILABLE_TETHER);
+ verify(mNMService, times(1)).setIpForwardingEnabled(true);
+ verify(mNMService, times(1)).startTethering(any(String[].class));
+ verifyNoMoreInteractions(mNMService);
+ verifyTetheringBroadcast(TEST_P2P_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
+ verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
+ // This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
+ // and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
+ assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
+
+ assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+
+ // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
+ // is being removed.
+ sendWifiP2pConnectionChanged(false, true, TEST_P2P_IFNAME);
+ mTethering.interfaceRemoved(TEST_P2P_IFNAME);
+ mLooper.dispatchAll();
+
+ verify(mNMService, times(1)).untetherInterface(TEST_P2P_IFNAME);
+ // {g,s}etInterfaceConfig() called twice for enabling and disabling IPv4.
+ verify(mNMService, times(2)).getInterfaceConfig(TEST_P2P_IFNAME);
+ verify(mNMService, times(2))
+ .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, times(1)).stopTethering();
+ verify(mNMService, times(1)).setIpForwardingEnabled(false);
+ verify(mUpstreamNetworkMonitor, never()).getCurrentPreferredUpstream();
+ verify(mUpstreamNetworkMonitor, never()).selectPreferredUpstreamType(any());
+ verifyNoMoreInteractions(mNMService);
+ // Asking for the last error after the per-interface state machine
+ // has been reaped yields an unknown interface error.
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+ }
+
+ private void workingWifiP2pGroupClient(
+ boolean emulateInterfaceStatusChanged) throws Exception {
+ if (emulateInterfaceStatusChanged) {
+ mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+ }
+ sendWifiP2pConnectionChanged(true, false, TEST_P2P_IFNAME);
+ mLooper.dispatchAll();
+
+ verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+ verify(mNMService, never())
+ .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
+ verify(mNMService, never()).setIpForwardingEnabled(true);
+ verify(mNMService, never()).startTethering(any(String[].class));
+
+ // Emulate externally-visible WifiP2pManager effects, when wifi p2p group
+ // is being removed.
+ sendWifiP2pConnectionChanged(false, false, TEST_P2P_IFNAME);
+ mTethering.interfaceRemoved(TEST_P2P_IFNAME);
+ mLooper.dispatchAll();
+
+ verify(mNMService, never()).untetherInterface(TEST_P2P_IFNAME);
+ verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+ verify(mNMService, never())
+ .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, never()).stopTethering();
+ verify(mNMService, never()).setIpForwardingEnabled(false);
+ verifyNoMoreInteractions(mNMService);
+ // Asking for the last error after the per-interface state machine
+ // has been reaped yields an unknown interface error.
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+ }
+
+ @Test
+ public void workingWifiP2pGroupOwnerWithIfaceChanged() throws Exception {
+ workingWifiP2pGroupOwner(true);
+ }
+
+ @Test
+ public void workingWifiP2pGroupOwnerSansIfaceChanged() throws Exception {
+ workingWifiP2pGroupOwner(false);
+ }
+
+ private void workingWifiP2pGroupOwnerLegacyMode(
+ boolean emulateInterfaceStatusChanged) throws Exception {
+ // change to legacy mode and update tethering information by chaning SIM
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs))
+ .thenReturn(new String[]{});
+ final int fakeSubId = 1234;
+ mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
+
+ if (emulateInterfaceStatusChanged) {
+ mTethering.interfaceStatusChanged(TEST_P2P_IFNAME, true);
+ }
+ sendWifiP2pConnectionChanged(true, true, TEST_P2P_IFNAME);
+ mLooper.dispatchAll();
+
+ verify(mNMService, never()).getInterfaceConfig(TEST_P2P_IFNAME);
+ verify(mNMService, never())
+ .setInterfaceConfig(eq(TEST_P2P_IFNAME), any(InterfaceConfiguration.class));
+ verify(mNMService, never()).tetherInterface(TEST_P2P_IFNAME);
+ verify(mNMService, never()).setIpForwardingEnabled(true);
+ verify(mNMService, never()).startTethering(any(String[].class));
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_P2P_IFNAME));
+ }
+ @Test
+ public void workingWifiP2pGroupOwnerLegacyModeWithIfaceChanged() throws Exception {
+ workingWifiP2pGroupOwnerLegacyMode(true);
+ }
+
+ @Test
+ public void workingWifiP2pGroupOwnerLegacyModeSansIfaceChanged() throws Exception {
+ workingWifiP2pGroupOwnerLegacyMode(false);
+ }
+
+ @Test
+ public void workingWifiP2pGroupClientWithIfaceChanged() throws Exception {
+ workingWifiP2pGroupClient(true);
+ }
+
+ @Test
+ public void workingWifiP2pGroupClientSansIfaceChanged() throws Exception {
+ workingWifiP2pGroupClient(false);
+ }
+
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 4ce4406211ce..c08f9b04f0df 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -95,7 +95,7 @@ genrule {
],
}
-cc_library_shared {
+cc_library {
name: "libstatslog",
host_supported: true,
generated_sources: ["statslog.cpp"],