[automerger skipped] Adjusted the timing of getting instance of the SatelliteController. am: 59d41454e0 -s ours
am skip reason: Merged-In Ib35cc76e44ec494e753cdff2e1b2afa4a84bb634 with SHA-1 ab1deb9351 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/27387817
Change-Id: I0b8086821a16fe49cb4ac7c84dd4526072fe5300
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/flags/Android.bp b/flags/Android.bp
index 8f363b6..1885032 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -21,6 +21,7 @@
aconfig_declarations {
name: "telephony_flags",
package: "com.android.internal.telephony.flags",
+ container: "system",
srcs: [
"calling.aconfig",
"data.aconfig",
@@ -32,7 +33,6 @@
"subscription.aconfig",
"uicc.aconfig",
"satellite.aconfig",
- "iwlan.aconfig",
- "telephony.aconfig",
+ "iwlan.aconfig"
],
}
diff --git a/flags/calling.aconfig b/flags/calling.aconfig
index e67ebc6..c1dc7e7 100644
--- a/flags/calling.aconfig
+++ b/flags/calling.aconfig
@@ -1,15 +1,31 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=breadley TARGET=24Q3
flag {
name: "simultaneous_calling_indications"
+ is_exported: true
namespace: "telephony"
description: "APIs that are used to notify simultaneous calling changes to other applications."
bug: "297446980"
+ is_exported: true
}
+# OWNER=yomna TARGET=24Q3
flag {
name: "show_call_fail_notification_for_2g_toggle"
namespace: "telephony"
description: "Used in DisconnectCause and TelephonyConnection if a non-emergency call fails on a device with no 2G, to guard whether a user can see an updated error message reminding the 2G is disabled and potentially disrupting their call connectivity"
bug: "300142897"
-}
\ No newline at end of file
+}
+
+# OWNER=stevestatia TARGET=24Q4
+flag {
+ name: "remove_country_code_from_local_singapore_calls"
+ namespace: "telephony"
+ description: "Fix bug where the country code is being shown when merging in local Singapore numbers to conference calls."
+ bug:"284416645"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/data.aconfig b/flags/data.aconfig
index 6334803..f93999b 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -1,5 +1,18 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=linggm TARGET=24Q4
+flag {
+ name: "keep_empty_requests_network"
+ namespace: "telephony"
+ description: "Don't tear down network even if no requests attached to it."
+ bug: "331301784"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=linggm TARGET=24Q3
flag {
name: "auto_data_switch_allow_roaming"
namespace: "telephony"
@@ -10,6 +23,7 @@
}
}
+# OWNER=linggm TARGET=24Q3
flag {
name: "auto_data_switch_rat_ss"
namespace: "telephony"
@@ -17,6 +31,7 @@
bug:"260928808"
}
+# OWNER=linggm TARGET=24Q2
flag {
name: "use_alarm_callback"
namespace: "telephony"
@@ -24,6 +39,7 @@
bug: "311476875"
}
+# OWNER=linggm TARGET=24Q2
flag {
name: "refine_preferred_data_profile_selection"
namespace: "telephony"
@@ -31,6 +47,7 @@
bug: "311476883"
}
+# OWNER=linggm TARGET=24Q2
flag {
name: "unthrottle_check_transport"
namespace: "telephony"
@@ -38,6 +55,7 @@
bug: "303922311"
}
+# OWNER=linggm TARGET=24Q1
flag {
name: "relax_ho_teardown"
namespace: "telephony"
@@ -45,6 +63,7 @@
bug: "270895912"
}
+# OWNER=linggm TARGET=24Q2
flag {
name: "allow_mmtel_in_non_vops"
namespace: "telephony"
@@ -52,6 +71,7 @@
bug: "241198464"
}
+# OWNER=jackyu TARGET=24Q2
flag {
name: "metered_embb_urlcc"
namespace: "telephony"
@@ -59,27 +79,34 @@
bug: "301310451"
}
+# OWNER=sarahchin TARGET=24Q3
flag {
name: "slicing_additional_error_codes"
+ is_exported: true
namespace: "telephony"
description: "Support additional slicing error codes and functionality."
bug: "307378699"
}
+# OWNER=nagendranb TARGET=24Q3
flag {
name: "apn_setting_field_support_flag"
+ is_exported: true
namespace: "telephony"
description: "Expose apn setting supporting field"
bug: "307038091"
}
+# OWNER=sangyun TARGET=24Q3
flag {
name: "network_validation"
+ is_exported: true
namespace: "telephony"
description: "Request network validation for data networks and response status."
bug:"286171724"
}
+# OWNER=nagendranb TARGET=24Q2
flag {
name: "notify_data_activity_changed_with_slot"
namespace: "telephony"
@@ -87,6 +114,7 @@
bug: "309896936"
}
+# OWNER=qingqi TARGET=24Q3
flag {
name: "vonr_enabled_metric"
namespace: "telephony"
@@ -94,6 +122,7 @@
bug:"288449751"
}
+# OWNER=willycwhu TARGET=24Q2
flag {
name: "ignore_existing_networks_for_internet_allowed_checking"
namespace: "telephony"
@@ -101,6 +130,7 @@
bug: "284420611"
}
+# OWNER=apsankar TARGET=24Q3
flag {
name: "data_call_session_stats_captures_cross_sim_calling"
namespace: "telephony"
@@ -108,6 +138,7 @@
bug: "313956117"
}
+# OWNER=jackyu TARGET=24Q2
flag {
name: "force_iwlan_mms"
namespace: "telephony"
@@ -115,6 +146,7 @@
bug: "316211526"
}
+# OWNER=sewook TARGET=24Q3
flag {
name: "reconnect_qualified_network"
namespace: "telephony"
@@ -122,9 +154,18 @@
bug: "319520561"
}
+# OWNER=jackyu TARGET=24Q3
flag {
name: "dsrs_diagnostics_enabled"
namespace: "telephony"
description: "Enable DSRS diagnostics."
bug: "319601607"
-}
\ No newline at end of file
+}
+
+# OWNER=jackyu TARGET=24Q3
+flag {
+ name: "data_rat_metric_enabled"
+ namespace: "telephony"
+ description: "Write DataRatStateChanged atom"
+ bug:"318519337"
+}
diff --git a/flags/domainselection.aconfig b/flags/domainselection.aconfig
index 2e1dfc8..623c3b6 100644
--- a/flags/domainselection.aconfig
+++ b/flags/domainselection.aconfig
@@ -1,5 +1,7 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=forestchoi TARGET=24Q3
flag {
name: "ap_domain_selection_enabled"
namespace: "telephony"
@@ -7,6 +9,7 @@
bug:"258112541"
}
+# OWNER=forestchoi TARGET=24Q3
flag {
name: "use_aosp_domain_selection_service"
namespace: "telephony"
@@ -14,13 +17,16 @@
bug:"258112541"
}
+# OWNER=forestchoi TARGET=24Q3
flag {
name: "use_oem_domain_selection_service"
+ is_exported: true
namespace: "telephony"
description: "This flag controls OEMs' domain selection service supported."
bug:"258112541"
}
+# OWNER=forestchoi TARGET=24Q3
flag {
name: "domain_selection_metrics_enabled"
namespace: "telephony"
diff --git a/flags/ims.aconfig b/flags/ims.aconfig
index d09259e..4eff505 100644
--- a/flags/ims.aconfig
+++ b/flags/ims.aconfig
@@ -1,5 +1,7 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=hyosunkim TARGET=24Q2
flag {
name: "conference_hold_unhold_changed_to_send_message"
namespace: "telephony"
@@ -7,6 +9,7 @@
bug:"288002989"
}
+# OWNER=joonhunshin TARGET=24Q2
flag {
name: "ignore_already_terminated_incoming_call_before_registering_listener"
namespace: "telephony"
@@ -14,6 +17,7 @@
bug:"289461637"
}
+# OWNER=joonhunshin TARGET=24Q2
flag {
name: "clear_cached_ims_phone_number_when_device_lost_ims_registration"
namespace: "telephony"
@@ -21,6 +25,7 @@
bug:"288002989"
}
+# OWNER=sangyun TARGET=24Q2
flag {
name: "update_ims_service_by_gathering_provisioning_changes"
namespace: "telephony"
@@ -28,13 +33,16 @@
bug:"302281114"
}
+# OWNER=shmun TARGET=24Q3
flag {
name: "add_rat_related_suggested_action_to_ims_registration"
+ is_exported: true
namespace: "telephony"
description: "This flag is for adding suggested actions related to RAT to ims registration"
bug:"290573256"
}
+# OWNER=joonhunshin TARGET=24Q3
flag {
name: "terminate_active_video_call_when_accepting_second_video_call_as_audio_only"
namespace: "telephony"
@@ -42,13 +50,16 @@
bug:"309548300"
}
+# OWNER=sewookseo TARGET=24Q3
flag {
name: "emergency_registration_state"
+ is_exported: true
namespace: "telephony"
description: "This flag is created to notify emergency registration state changed."
bug:"312101946"
}
+# OWNER=apsankar TARGET=24Q3
flag {
name: "call_extra_for_non_hold_supported_carriers"
namespace: "telephony"
@@ -56,9 +67,51 @@
bug:"315993953"
}
+# OWNER=joonhunshin TARGET=24Q3
flag {
name: "update_roaming_state_to_set_wfc_mode"
namespace: "telephony"
description: "This flag updates roaming state to set wfc mode"
bug:"317298331"
}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "enable_sip_subscribe_retry"
+ namespace: "telephony"
+ description: "This flag controls whether framework supports SIP subscribe retry or not"
+ bug:"297023230"
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "answer_audio_only_when_answering_via_mmi_code"
+ namespace: "telephony"
+ description: "This flag changes the media type when answering incoming call via MMI code"
+ bug:"286499659"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "notify_initial_ims_provisioning_status"
+ namespace: "telephony"
+ description: "This flag allows to notify initial IMS provisioning status when IFeatureProvisioningCallback registered or ImsService connected"
+ bug:"330082572"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "set_number_of_sim_for_ims_enable"
+ namespace: "telephony"
+ description: "This flag allows to set number of SIM for IMS enable/disable for each slot when the eSIM is added while the binding with ImsService exists"
+ bug:"331971397"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/iwlan.aconfig b/flags/iwlan.aconfig
index 0dc9f8d..f16ee38 100644
--- a/flags/iwlan.aconfig
+++ b/flags/iwlan.aconfig
@@ -1,13 +1,19 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=jmunikrishna TARGET=24Q3
flag {
name: "enable_aead_algorithms"
+ is_exported: true
namespace: "telephony"
description: "Add AEAD algorithms AES-GCM-8, AES-GCM-12 and AES-GCM-16 to IWLAN"
bug:"306119890"
}
+
+# OWNER=jmunikrishna TARGET=24Q3
flag {
name: "enable_multiple_sa_proposals"
+ is_exported: true
namespace: "telephony"
description: "Add multiple proposals of cipher suites in IKE SA and Child SA"
bug:"287296642"
diff --git a/flags/messaging.aconfig b/flags/messaging.aconfig
index 1ba89ba..1030ba7 100644
--- a/flags/messaging.aconfig
+++ b/flags/messaging.aconfig
@@ -1,12 +1,7 @@
package: "com.android.internal.telephony.flags"
+container: "system"
-flag {
- name: "reject_bad_sub_id_interaction"
- namespace: "telephony"
- description: "Previously, the DB allows insertion of a random sub Id, but doesn't allow query it. This change rejects such interaction."
- bug: "294125411"
-}
-
+# OWNER=hwangoo TARGET=24Q2
flag {
name: "sms_domain_selection_enabled"
namespace: "telephony"
@@ -14,9 +9,33 @@
bug: "262804071"
}
+# OWNER=tnd TARGET=24Q3
flag {
name: "mms_disabled_error"
+ is_exported: true
namespace: "telephony"
description: "This flag controls the support of the new MMS error code MMS_ERROR_MMS_DISABLED."
bug: "305062594"
+}
+
+# OWNER=linggm TARGET=24Q4
+flag {
+ name: "mms_get_apn_from_pdsc"
+ namespace: "telephony"
+ description: "This flag controls get APN details from PDSC instead of telephony provider."
+ bug: "324280016"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=stevestatia TARGET=24Q3
+flag {
+ name: "unregister_sms_broadcast_receiver_from_cat_service"
+ namespace: "telephony"
+ description: "This flag will unregister the sms broadcast receiver in the CatService when the process is disposed."
+ bug: "338936403"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 1e714c5..9d5cbd6 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -1,5 +1,18 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=linggm TARGET=24Q3
+flag {
+ name: "combine_ril_death_handle"
+ namespace: "telephony"
+ description: "Upon radio service death, combine its handling to prevent race condition"
+ bug:"319612362"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=tjstuart TARGET=24Q3
flag {
name: "do_not_override_precise_label"
namespace: "telephony"
@@ -8,6 +21,7 @@
is_fixed_read_only: true
}
+# OWNER=tnd TARGET=24Q1
flag {
name: "log_mms_sms_database_access_info"
namespace: "telephony"
@@ -15,6 +29,7 @@
bug: "275225402"
}
+# OWNER=tjstuart TARGET=24Q3
flag {
name: "stop_spamming_emergency_notification"
namespace: "telephony"
@@ -22,13 +37,16 @@
bug: "275225402"
}
+# OWNER=avinashmp TARGET=24Q3
flag {
name: "enable_wps_check_api_flag"
+ is_exported: true
namespace: "telephony"
description: "Enable system api isWpsCallNumber. Its an utility api to check if the dialed number is for Wireless Priority Service call."
bug: "304272356"
}
+# OWNER=grantmenke TARGET=24Q3
flag {
name: "ensure_access_to_call_settings_is_restricted"
namespace: "telephony"
@@ -36,6 +54,7 @@
bug: "309655251"
}
+# OWNER=sangyun TARGET=24Q2
flag {
name: "reorganize_roaming_notification"
namespace: "telephony"
@@ -43,6 +62,7 @@
bug: "310594087"
}
+# OWNER=sangyun TARGET=24Q2
flag {
name: "dismiss_network_selection_notification_on_sim_disable"
namespace: "telephony"
@@ -50,6 +70,7 @@
bug: "310594186"
}
+# OWNER=nagendranb TARGET=24Q3
flag {
name: "enable_telephony_analytics"
namespace: "telephony"
@@ -57,20 +78,25 @@
bug: "309896524"
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "show_call_id_and_call_waiting_in_additional_settings_menu"
+ is_exported: true
namespace: "telephony"
description: "Expose carrier config KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL and KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL."
bug: "310264981"
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "reset_mobile_network_settings"
+ is_exported: true
namespace: "telephony"
description: "Allows applications to launch Reset Mobile Network Settings page in Settings app."
bug:"271921464"
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "fix_crash_on_getting_config_when_phone_is_gone"
namespace: "telephony"
@@ -81,6 +107,7 @@
}
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "add_anomaly_when_notify_config_changed_with_invalid_phone"
namespace: "telephony"
@@ -91,6 +118,7 @@
}
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "hide_preinstalled_carrier_app_at_most_once"
namespace: "telephony"
@@ -100,3 +128,92 @@
purpose: PURPOSE_BUGFIX
}
}
+
+# OWNER=sangyun TARGET=24Q3
+flag {
+ name: "roaming_notification_for_single_data_network"
+ namespace: "telephony"
+ description: "Fix bug where roaming notification was not shown on a single data network."
+ bug:"249908996"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "enforce_telephony_feature_mapping"
+ namespace: "telephony"
+ description: "This flag controls telephony feature flags mapping."
+ bug:"297989574"
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "enforce_telephony_feature_mapping_for_public_apis"
+ namespace: "telephony"
+ description: "This flag controls telephony feature flags mapping for public APIs and CTS."
+ bug:"297989574"
+}
+
+# OWNER=stevestatia TARGET=24Q3
+flag {
+ name: "prevent_system_server_and_phone_deadlock"
+ namespace: "telephony"
+ description: "This flag controls the order of the binder to prevent deadlock in system_server"
+ bug: "315973270"
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "prevent_invocation_repeat_of_ril_call_when_device_does_not_support_voice"
+ namespace: "telephony"
+ description: "This flag prevents repeat invocation of call related APIs in RIL when the device is not voice capable"
+ bug: "290833783"
+}
+
+# OWNER=jackyu TARGET=24Q3
+flag {
+ name: "minimal_telephony_cdm_check"
+ namespace: "telephony"
+ description: "This flag disables Calling/Data/Messaging features if their respective feature is missing"
+ bug: "310710841"
+}
+
+# OWNER=jackyu TARGET=24Q3
+flag {
+ name: "minimal_telephony_managers_conditional_on_features"
+ namespace: "telephony"
+ description: "This flag enables checking for telephony features before initializing corresponding managers"
+ bug: "310710841"
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "set_no_reply_timer_for_cfnry"
+ namespace: "telephony"
+ description: "This flag supports setting the no reply timer for CFNRy based on carrier config"
+ bug:"314732435"
+}
+
+# OWNER=joonhunshin TARGET=24Q3
+flag {
+ name: "change_method_of_obtaining_ims_registration_radio_tech"
+ namespace: "telephony"
+ description: "This flag changes the method of obtaining IMS registration radio technology"
+ bug:"330120237"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+# OWNER=sasindran TARGET=24Q3
+flag {
+ name: "use_relaxed_id_match"
+ namespace: "telephony"
+ description: "This flag supports relaxed id match for radio state changes"
+ bug:"336916327"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/network.aconfig b/flags/network.aconfig
index ab917f0..7c09ba3 100644
--- a/flags/network.aconfig
+++ b/flags/network.aconfig
@@ -1,5 +1,7 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=nharold TARGET=24Q1
flag {
name: "enable_carrier_config_n1_control_attempt2"
namespace: "telephony"
@@ -11,20 +13,25 @@
}
}
+# OWNER=sarahchin TARGET=24Q1
flag {
name: "hide_roaming_icon"
+ is_exported: true
namespace: "telephony"
description: "Allow carriers to hide the roaming (R) icon when roaming."
bug: "301467052"
}
+# OWNER=cukie TARGET=24Q3
flag {
name: "enable_identifier_disclosure_transparency"
+ is_exported: true
namespace: "telephony"
description: "Guards APIs for enabling and disabling identifier disclosure transparency"
bug: "276752426"
}
+# OWNER=cukie TARGET=24Q3
flag {
name: "enable_identifier_disclosure_transparency_unsol_events"
namespace: "telephony"
@@ -32,13 +39,16 @@
bug: "276752426"
}
+# OWNER=cukie TARGET=24Q3
flag {
name: "enable_modem_cipher_transparency"
+ is_exported: true
namespace: "telephony"
description: "Guards APIs for enabling and disabling modem cipher transparency."
bug: "283336425"
}
+# OWNER=cukie TARGET=24Q3
flag {
name: "enable_modem_cipher_transparency_unsol_events"
namespace: "telephony"
@@ -46,13 +56,16 @@
bug: "283336425"
}
+# OWNER=songferngwang TARGET=24Q3
flag {
name: "hide_prefer_3g_item"
+ is_exported: true
namespace: "telephony"
description: "Used in the Preferred Network Types menu to determine if the 3G option is displayed."
bug: "310639009"
}
+# OWNER=sarahchin TARGET=24Q2
flag {
name: "support_nr_sa_rrc_idle"
namespace: "telephony"
@@ -60,9 +73,23 @@
bug: "298233308"
}
+# OWNER=nharold TARGET=24Q3
flag {
name: "network_registration_info_reject_cause"
+ is_exported: true
namespace: "telephony"
description: "Elevate NRI#getRejectCause from System to Public"
bug: "239730435"
}
+
+# OWNER=sangyun TARGET=24Q3
+flag {
+ name: "backup_and_restore_for_enable_2g"
+ namespace: "telephony"
+ description: "Support backup & restore for allow 2g (setting) option."
+ bug:"314734614"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/flags/satellite.aconfig b/flags/satellite.aconfig
index 798ce40..27ab0b1 100644
--- a/flags/satellite.aconfig
+++ b/flags/satellite.aconfig
@@ -1,19 +1,25 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=amallampati TARGET=24Q3
flag {
name: "oem_enabled_satellite_flag"
+ is_exported: true
namespace: "telephony"
description: "This flag controls satellite communication supported by OEMs."
bug:"291811962"
}
+# OWNER=amallampati TARGET=24Q3
flag {
name: "carrier_enabled_satellite_flag"
+ is_exported: true
namespace: "telephony"
description: "This flag controls satellite communication supported by carriers."
bug:"296437388"
}
+# OWNER=nagendranb TARGET=24Q3
flag {
name: "satellite_internet"
namespace: "telephony"
diff --git a/flags/subscription.aconfig b/flags/subscription.aconfig
index cebedd5..32e8f2d 100644
--- a/flags/subscription.aconfig
+++ b/flags/subscription.aconfig
@@ -1,26 +1,34 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=linggm TARGET=24Q3
flag {
name: "work_profile_api_split"
+ is_exported: true
namespace: "telephony"
description: "To support separation between personal and work from TelephonyManager and SubscriptionManager API perspective."
bug: "296076674"
}
+# OWNER=linggm TARGET=24Q3
flag {
name: "enforce_subscription_user_filter"
+ is_exported: true
namespace: "telephony"
description: "Enabled flag means subscriptions enforce filtering result base on calling user handle. It marks the telephony completion of user filtering."
bug: "296076674"
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "data_only_cellular_service"
+ is_exported: true
namespace: "telephony"
description: "Supports customized cellular service capabilities per subscription."
bug: "296097429"
}
+# OWNER=rambowang TARGET=24Q3
flag {
name: "data_only_service_allow_emergency_call_only"
namespace: "telephony"
@@ -28,16 +36,32 @@
bug: "296097429"
}
+# OWNER=hhshin TARGET=24Q3
flag {
name: "support_psim_to_esim_conversion"
+ is_exported: true
namespace: "telephony"
description: "Support the psim to esim conversion."
bug: "315073761"
}
+# OWNER=bookatz TARGET=24Q3
flag {
name: "subscription_user_association_query"
+ is_exported: true
namespace: "telephony"
description: "Supports querying if a subscription is associated with the caller"
bug: "325045841"
-}
\ No newline at end of file
+}
+
+# OWNER=nharold TARGET=24Q3
+flag {
+ name: "safer_get_phone_number"
+ namespace: "telephony"
+ description: "Safety and performance improvements for getPhoneNumber()"
+ bug: "317673478"
+
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/telephony.aconfig b/flags/telephony.aconfig
deleted file mode 100644
index 9ef70b1..0000000
--- a/flags/telephony.aconfig
+++ /dev/null
@@ -1,43 +0,0 @@
-package: "com.android.internal.telephony.flags"
-
-flag {
- name: "enforce_telephony_feature_mapping"
- namespace: "telephony"
- description: "This flag controls telephony feature flags mapping."
- bug:"297989574"
-}
-
-flag {
- name: "enforce_telephony_feature_mapping_for_public_apis"
- namespace: "telephony"
- description: "This flag controls telephony feature flags mapping for public APIs and CTS."
- bug:"297989574"
-}
-
-flag {
- name: "prevent_system_server_and_phone_deadlock"
- namespace: "telephony"
- description: "This flag controls the order of the binder to prevent deadlock in system_server"
- bug: "315973270"
-}
-
-flag {
- name: "prevent_invocation_repeat_of_ril_call_when_device_does_not_support_voice"
- namespace: "telephony"
- description: "This flag prevents repeat invocation of call related APIs in RIL when the device is not voice capable"
- bug: "290833783"
-}
-
-flag {
- name: "minimal_telephony_cdm_check"
- namespace: "telephony"
- description: "This flag disables Calling/Data/Messaging features if their respective feature is missing"
- bug: "310710841"
-}
-
-flag {
- name: "minimal_telephony_managers_conditional_on_features"
- namespace: "telephony"
- description: "This flag enables checking for telephony features before initializing corresponding managers"
- bug: "310710841"
-}
diff --git a/flags/uicc.aconfig b/flags/uicc.aconfig
index c1b860f..2d7b643 100644
--- a/flags/uicc.aconfig
+++ b/flags/uicc.aconfig
@@ -1,32 +1,52 @@
package: "com.android.internal.telephony.flags"
+container: "system"
+# OWNER=jayachandranc TARGET=24Q3
flag {
name: "esim_bootstrap_provisioning_flag"
namespace: "telephony"
description: "This flag controls eSIM Bootstrap provisioning feature support."
bug:"298567545"
}
+
+# OWNER=arunvoddu TARGET=24Q3
flag {
name: "imsi_key_retry_download_on_phone_unlock"
namespace: "telephony"
description: "This flag controls to download the IMSI encryption keys after user unlocks the phone."
bug:"303780982"
}
+
+# OWNER=arunvoddu TARGET=24Q3
flag {
name: "carrier_restriction_status"
+ is_exported: true
namespace: "telephony"
description: "This flag controls the visibility of the getCarrierRestrictionStatus in carrierRestrictionRules class."
bug:"313553044"
}
+
+# OWNER=arunvoddu TARGET=24Q3
flag {
name: "carrier_restriction_rules_enhancement"
namespace: "telephony"
description: "This flag controls the new enhancements to the existing carrier restrictions rules"
bug:"317226653"
}
+
+# OWNER=rafahs TARGET=24Q3
flag {
name: "esim_available_memory"
+ is_exported: true
namespace: "telephony"
description: "This flag controls eSIM available memory feature."
bug:"318348580"
}
+
+# OWNER=rambowang TARGET=24Q3
+flag {
+ name: "cleanup_open_logical_channel_record_on_dispose"
+ namespace: "telephony"
+ description: "This flag cleans up the OpenLogicalChannelRecord once SIM is removed"
+ bug:"335046531"
+}
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 46a2400..6a3dcbd 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -23,7 +23,7 @@
// Holds atoms to store on persist storage in case of power cycle or process crash.
// NOTE: using int64 rather than google.protobuf.Timestamp for timestamps simplifies implementation.
-// Next id: 70
+// Next id: 80
message PersistAtoms {
/* Aggregated RAT usage during the call. */
repeated VoiceCallRatUsage voice_call_rat_usage = 1;
@@ -231,6 +231,36 @@
/* Timestamp of last satellite_sos_message_recommender pull. */
optional int64 satellite_sos_message_recommender_pull_timestamp_millis = 69;
+
+ /* Data Network Validation statistics and information. */
+ repeated DataNetworkValidation data_network_validation = 70;
+
+ /* Timestamp of last data_network_validation pull. */
+ optional int64 data_network_validation_pull_timestamp_millis = 71;
+
+ /* Snapshot of carrier roaming satellite session. */
+ repeated CarrierRoamingSatelliteSession carrier_roaming_satellite_session = 72;
+
+ /* Timestamp of last carrier_roaming_satellite_session pull. */
+ optional int64 carrier_roaming_satellite_session_pull_timestamp_millis = 73;
+
+ /* Snapshot of carrier roaming satellite controller stats. */
+ repeated CarrierRoamingSatelliteControllerStats carrier_roaming_satellite_controller_stats = 74;
+
+ /* Timestamp of last carrier_roaming_satellite_controller_stats pull. */
+ optional int64 carrier_roaming_satellite_controller_stats_pull_timestamp_millis = 75;
+
+ /* Snapshot of satellite entitlement. */
+ repeated SatelliteEntitlement satellite_entitlement = 76;
+
+ /* Timestamp of last satellite_entitlement pull. */
+ optional int64 satellite_entitlement_pull_timestamp_millis = 77;
+
+ /* Snapshot of satellite config updater. */
+ repeated SatelliteConfigUpdater satellite_config_updater = 78;
+
+ /* Timestamp of last satellite_config_updater pull. */
+ optional int64 satellite_config_updater_pull_timestamp_millis = 79;
}
// The canonical versions of the following enums live in:
@@ -375,6 +405,7 @@
optional bool is_non_dds = 22;
optional bool is_iwlan_cross_sim = 23;
optional bool is_ntn = 24;
+ optional bool is_satellite_transport = 25;
}
message CellularServiceState {
@@ -464,6 +495,12 @@
PRIORITIZE_BANDWIDTH = 2;
CBS = 3;
ENTERPRISE = 4;
+ SATELLITE_INTERNET_RESTRICTED = 5;
+ SATELLITE_MMS_RESTRICTED = 6;
+ SATELLITE_IMS_RESTRICTED = 7;
+ SATELLITE_XCAP_RESTRICTED = 8;
+ SATELLITE_EIMS_RESTRICTED = 9;
+ SATELLITE_SUPL_RESTRICTED =10;
}
optional int32 carrier_id = 1;
optional NetworkCapability capability = 2;
@@ -716,3 +753,57 @@
optional int32 recommending_handover_type = 7;
optional bool is_satellite_allowed_in_current_location = 8;
}
+
+message DataNetworkValidation {
+ optional int32 network_type = 1;
+ optional int32 apn_type_bitmask = 2;
+ optional int32 signal_strength = 3;
+ optional int32 validation_result = 4;
+ optional int64 elapsed_time_in_millis = 5;
+ optional bool handover_attempted = 6;
+ optional int32 network_validation_count = 7;
+}
+
+message CarrierRoamingSatelliteSession {
+ optional int32 carrier_id = 1;
+ optional bool is_ntn_roaming_in_home_country = 2;
+ optional int32 total_satellite_mode_time_sec = 3;
+ optional int32 number_of_satellite_connections = 4;
+ optional int32 avg_duration_of_satellite_connection_sec = 5;
+ optional int32 satellite_connection_gap_min_sec = 6;
+ optional int32 satellite_connection_gap_avg_sec = 7;
+ optional int32 satellite_connection_gap_max_sec = 8;
+ optional int32 rsrp_avg = 9;
+ optional int32 rsrp_median = 10;
+ optional int32 rssnr_avg = 11;
+ optional int32 rssnr_median = 12;
+ optional int32 count_of_incoming_sms = 13;
+ optional int32 count_of_outgoing_sms = 14;
+ optional int32 count_of_incoming_mms = 15;
+ optional int32 count_of_outgoing_mms = 16;
+}
+
+message CarrierRoamingSatelliteControllerStats {
+ optional int32 config_data_source = 1;
+ optional int32 count_of_entitlement_status_query_request = 2;
+ optional int32 count_of_satellite_config_update_request = 3;
+ optional int32 count_of_satellite_notification_displayed = 4;
+ optional int32 satellite_session_gap_min_sec = 5;
+ optional int32 satellite_session_gap_avg_sec = 6;
+ optional int32 satellite_session_gap_max_sec = 7;
+}
+
+message SatelliteEntitlement {
+ optional int32 carrier_id = 1;
+ optional int32 result = 2;
+ optional int32 entitlement_status = 3;
+ optional bool is_retry = 4;
+ optional int32 count = 5;
+}
+
+message SatelliteConfigUpdater {
+ optional int32 config_version = 1;
+ optional int32 oem_config_result = 2;
+ optional int32 carrier_config_result = 3;
+ optional int32 count = 4;
+}
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index b87728b..92f62cc 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -259,8 +259,8 @@
// Roaming type
enum RoamingType {
- // Unknown. The default value. Different from ROAMING_TYPE_UNKNOWN.
- UNKNOWN = -1;
+ // Undefined. The default value. Different from ROAMING_TYPE_UNKNOWN.
+ ROAMING_TYPE_UNDEFINED = -1;
// In home network
ROAMING_TYPE_NOT_ROAMING = 0;
@@ -346,10 +346,10 @@
optional TelephonyOperator data_operator = 2;
// Current voice network roaming type
- optional RoamingType voice_roaming_type = 3 [default = UNKNOWN];
+ optional RoamingType voice_roaming_type = 3 [default = ROAMING_TYPE_UNDEFINED];
// Current data network roaming type
- optional RoamingType data_roaming_type = 4 [default = UNKNOWN];
+ optional RoamingType data_roaming_type = 4 [default = ROAMING_TYPE_UNDEFINED];
// Current voice radio technology
optional RadioAccessTechnology voice_rat = 5 [default = UNKNOWN];
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index 863db93..8364c0a 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -33,6 +33,7 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import java.security.PublicKey;
@@ -297,7 +298,12 @@
final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
.createForSubscriptionId(subId);
int carrierId = telephonyManager.getSimCarrierId();
- deleteCarrierInfoForImsiEncryption(context, subId, carrierId);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ String simOperator = telephonyManager.getSimOperator();
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId, simOperator);
+ } else {
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId);
+ }
Intent resetIntent = new Intent(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
SubscriptionManager.putPhoneIdAndSubIdExtra(resetIntent, mPhoneId);
context.sendBroadcastAsUser(resetIntent, UserHandle.ALL);
@@ -312,13 +318,29 @@
*/
public static void deleteCarrierInfoForImsiEncryption(Context context, int subId,
int carrierId) {
+ deleteCarrierInfoForImsiEncryption(context, subId, carrierId, null);
+ }
+
+ /**
+ * Deletes all the keys for a given Carrier from the device keystore.
+ * @param context Context
+ * @param subId SubscriptionId
+ * @param carrierId delete the key which matches the carrierId
+ * @param simOperator delete the key which matches the MCCMNC
+ *
+ */
+ public static void deleteCarrierInfoForImsiEncryption(Context context, int subId,
+ int carrierId, String simOperator) {
Log.i(LOG_TAG, "deleting carrier key from db for subId=" + subId);
String mcc = "";
String mnc = "";
- final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
- .createForSubscriptionId(subId);
- String simOperator = telephonyManager.getSimOperator();
+ if (TextUtils.isEmpty(simOperator)) {
+ final TelephonyManager telephonyManager = context.getSystemService(
+ TelephonyManager.class)
+ .createForSubscriptionId(subId);
+ simOperator = telephonyManager.getSimOperator();
+ }
if (!TextUtils.isEmpty(simOperator)) {
mcc = simOperator.substring(0, 3);
mnc = simOperator.substring(3);
diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
index 9143f21..10a3a32 100644
--- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
+++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
@@ -18,6 +18,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.DownloadManager;
import android.app.KeyguardManager;
@@ -27,6 +28,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
@@ -34,19 +37,22 @@
import android.os.UserManager;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.flags.Flags;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
@@ -57,6 +63,7 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
+import java.util.List;
import java.util.Random;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipException;
@@ -99,6 +106,8 @@
private static final int EVENT_ALARM_OR_CONFIG_CHANGE = 0;
private static final int EVENT_DOWNLOAD_COMPLETE = 1;
+ private static final int EVENT_NETWORK_AVAILABLE = 2;
+ private static final int EVENT_SCREEN_UNLOCKED = 3;
private static final int[] CARRIER_KEY_TYPES = {TelephonyManager.KEY_TYPE_EPDG,
@@ -111,47 +120,77 @@
private boolean mAllowedOverMeteredNetwork = false;
private boolean mDeleteOldKeyAfterDownload = false;
private boolean mIsRequiredToHandleUnlock;
- private TelephonyManager mTelephonyManager;
+ private final TelephonyManager mTelephonyManager;
private UserManager mUserManager;
-
@VisibleForTesting
- public String mMccMncForDownload;
- public int mCarrierId;
+ public String mMccMncForDownload = "";
+ public int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
@VisibleForTesting
public long mDownloadId;
- private final FeatureFlags mFeatureFlags;
+ private DefaultNetworkCallback mDefaultNetworkCallback;
+ private ConnectivityManager mConnectivityManager;
+ private KeyguardManager mKeyguardManager;
- public CarrierKeyDownloadManager(Phone phone, FeatureFlags featureFlags) {
+ public CarrierKeyDownloadManager(Phone phone) {
mPhone = phone;
- mFeatureFlags = featureFlags;
mContext = phone.getContext();
IntentFilter filter = new IntentFilter();
filter.addAction(INTENT_KEY_RENEWAL_ALARM_PREFIX);
filter.addAction(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
- filter.addAction(Intent.ACTION_USER_PRESENT);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ }
mContext.registerReceiver(mBroadcastReceiver, filter, null, phone);
mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mPhone.getSubId());
- mUserManager = mContext.getSystemService(UserManager.class);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ } else {
+ mUserManager = mContext.getSystemService(UserManager.class);
+ }
CarrierConfigManager carrierConfigManager = mContext.getSystemService(
CarrierConfigManager.class);
// Callback which directly handle config change should be executed on handler thread
carrierConfigManager.registerCarrierConfigChangeListener(this::post,
(slotIndex, subId, carrierId, specificCarrierId) -> {
- boolean isUserUnlocked = mUserManager.isUserUnlocked();
-
- if (isUserUnlocked && slotIndex == mPhone.getPhoneId()) {
- Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex);
- handleAlarmOrConfigChange();
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ logd("CarrierConfig changed slotIndex = " + slotIndex + " subId = " + subId
+ + " CarrierId = " + carrierId + " phoneId = "
+ + mPhone.getPhoneId());
+ // Below checks are necessary to optimise the logic.
+ if ((slotIndex == mPhone.getPhoneId()) && (carrierId > 0
+ || !TextUtils.isEmpty(
+ mMccMncForDownload))) {
+ mCarrierId = carrierId;
+ updateSimOperator();
+ // If device is screen locked do not proceed to handle
+ // EVENT_ALARM_OR_CONFIG_CHANGE
+ if (mKeyguardManager.isDeviceLocked()) {
+ logd("Device is Locked");
+ mIsRequiredToHandleUnlock = true;
+ } else {
+ logd("Carrier Config changed: slotIndex=" + slotIndex);
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
+ }
} else {
- Log.d(LOG_TAG, "User is locked");
- mContext.registerReceiver(mUserUnlockedReceiver, new IntentFilter(
- Intent.ACTION_USER_UNLOCKED));
+ boolean isUserUnlocked = mUserManager.isUserUnlocked();
+
+ if (isUserUnlocked && slotIndex == mPhone.getPhoneId()) {
+ Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex);
+ handleAlarmOrConfigChange();
+ } else {
+ Log.d(LOG_TAG, "User is locked");
+ mContext.registerReceiver(mUserUnlockedReceiver, new IntentFilter(
+ Intent.ACTION_USER_UNLOCKED));
+ }
}
});
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
}
+ // TODO remove this method upon imsiKeyRetryDownloadOnPhoneUnlock enabled.
private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -167,7 +206,7 @@
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
- Log.d(LOG_TAG, "Download Complete");
+ logd("Download Complete");
sendMessage(obtainMessage(EVENT_DOWNLOAD_COMPLETE,
intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)));
}
@@ -180,27 +219,36 @@
String action = intent.getAction();
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
int phoneId = mPhone.getPhoneId();
- if (action.equals(INTENT_KEY_RENEWAL_ALARM_PREFIX)) {
- int slotIndexExtra = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, -1);
- if (slotIndexExtra == slotIndex) {
- Log.d(LOG_TAG, "Handling key renewal alarm: " + action);
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ switch (action) {
+ case INTENT_KEY_RENEWAL_ALARM_PREFIX -> {
+ int slotIndexExtra = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
+ -1);
+ if (slotIndexExtra == slotIndex) {
+ logd("Handling key renewal alarm: " + action);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ updateSimOperator();
+ }
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
}
- } else if (action.equals(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD)) {
- if (phoneId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
- SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
- Log.d(LOG_TAG, "Handling reset intent: " + action);
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ case TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD -> {
+ if (phoneId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
+ logd("Handling reset intent: " + action);
+ sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ }
}
- } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
- // The Carrier key download fails when SIM is inserted while device is locked
- // hence adding a retry logic when device is unlocked.
- Log.d(LOG_TAG,
- "device unlocked, isRequiredToHandleUnlock = " + mIsRequiredToHandleUnlock
- + ", slotIndex = " + slotIndex);
- if (mIsRequiredToHandleUnlock) {
- mIsRequiredToHandleUnlock = false;
- sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
+ case Intent.ACTION_USER_UNLOCKED -> {
+ // The Carrier key download fails when SIM is inserted while device is locked
+ // hence adding a retry logic when device is unlocked.
+ logd("device fully unlocked, isRequiredToHandleUnlock = "
+ + mIsRequiredToHandleUnlock
+ + ", slotIndex = " + slotIndex + " hasActiveDataNetwork = " + (
+ mConnectivityManager.getActiveNetwork() != null));
+ if (mIsRequiredToHandleUnlock) {
+ mIsRequiredToHandleUnlock = false;
+ sendEmptyMessage(EVENT_SCREEN_UNLOCKED);
+ }
}
}
}
@@ -209,76 +257,124 @@
@Override
public void handleMessage (Message msg) {
switch (msg.what) {
- case EVENT_ALARM_OR_CONFIG_CHANGE:
- handleAlarmOrConfigChange();
- break;
- case EVENT_DOWNLOAD_COMPLETE:
+ case EVENT_ALARM_OR_CONFIG_CHANGE, EVENT_NETWORK_AVAILABLE, EVENT_SCREEN_UNLOCKED ->
+ handleAlarmOrConfigChange();
+ case EVENT_DOWNLOAD_COMPLETE -> {
long carrierKeyDownloadIdentifier = (long) msg.obj;
- String currentMccMnc = getSimOperator();
- int carrierId = getSimCarrierId();
+ String currentMccMnc = Flags.imsiKeyRetryDownloadOnPhoneUnlock()
+ ? mTelephonyManager.getSimOperator(mPhone.getSubId()) : getSimOperator();
+ int carrierId = Flags.imsiKeyRetryDownloadOnPhoneUnlock()
+ ? mTelephonyManager.getSimCarrierId() : getSimCarrierId();
if (isValidDownload(currentMccMnc, carrierKeyDownloadIdentifier, carrierId)) {
onDownloadComplete(carrierKeyDownloadIdentifier, currentMccMnc, carrierId);
- onPostDownloadProcessing(carrierKeyDownloadIdentifier);
+ onPostDownloadProcessing();
}
- break;
+ }
}
}
- private void onPostDownloadProcessing(long carrierKeyDownloadIdentifier) {
+ private void onPostDownloadProcessing() {
resetRenewalAlarm();
- cleanupDownloadInfo();
-
+ if(Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mDownloadId = -1;
+ } else {
+ cleanupDownloadInfo();
+ }
// unregister from DOWNLOAD_COMPLETE
mContext.unregisterReceiver(mDownloadReceiver);
}
private void handleAlarmOrConfigChange() {
- if (carrierUsesKeys()) {
- if (areCarrierKeysAbsentOrExpiring()) {
- boolean downloadStartedSuccessfully = downloadKey();
- // if the download was attempted, but not started successfully, and if carriers uses
- // keys, we'll still want to renew the alarms, and try downloading the key a day
- // later.
- if (!downloadStartedSuccessfully) {
- // If download fails due to the device lock, we will reattempt once the device
- // is unlocked.
- if (mFeatureFlags.imsiKeyRetryDownloadOnPhoneUnlock()) {
- KeyguardManager keyguardManager = mContext.getSystemService(
- KeyguardManager.class);
- if (keyguardManager.isKeyguardSecure()) {
- Log.e(LOG_TAG, "Key download failed in device lock state");
- mIsRequiredToHandleUnlock = true;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ if (carrierUsesKeys()) {
+ if (areCarrierKeysAbsentOrExpiring()) {
+ boolean hasActiveDataNetwork =
+ (mConnectivityManager.getActiveNetwork() != null);
+ boolean downloadStartedSuccessfully = hasActiveDataNetwork && downloadKey();
+ // if the download was attempted, but not started successfully, and if
+ // carriers uses keys, we'll still want to renew the alarms, and try
+ // downloading the key a day later.
+ int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
+ if (downloadStartedSuccessfully) {
+ unregisterDefaultNetworkCb(slotIndex);
+ } else {
+ // If download fails due to the device lock, we will reattempt once the
+ // device is unlocked.
+ mIsRequiredToHandleUnlock = mKeyguardManager.isDeviceLocked();
+ loge("hasActiveDataConnection = " + hasActiveDataNetwork
+ + " isDeviceLocked = " + mIsRequiredToHandleUnlock);
+ if (!hasActiveDataNetwork) {
+ registerDefaultNetworkCb(slotIndex);
}
+ resetRenewalAlarm();
}
- resetRenewalAlarm();
}
+ logd("handleAlarmOrConfigChange :: areCarrierKeysAbsentOrExpiring returned false");
} else {
- return;
+ cleanupRenewalAlarms();
+ if (!isOtherSlotHasCarrier()) {
+ // delete any existing alarms.
+ mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId(), getSimOperator());
+ }
+ cleanupDownloadInfo();
}
} else {
- // delete any existing alarms.
- cleanupRenewalAlarms();
- mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId());
-
+ if (carrierUsesKeys()) {
+ if (areCarrierKeysAbsentOrExpiring()) {
+ boolean downloadStartedSuccessfully = downloadKey();
+ // if the download was attempted, but not started successfully, and if
+ // carriers uses keys, we'll still want to renew the alarms, and try
+ // downloading the key a day later.
+ if (!downloadStartedSuccessfully) {
+ resetRenewalAlarm();
+ }
+ }
+ } else {
+ // delete any existing alarms.
+ cleanupRenewalAlarms();
+ mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId());
+ }
}
}
+ private boolean isOtherSlotHasCarrier() {
+ SubscriptionManager subscriptionManager = mPhone.getContext().getSystemService(
+ SubscriptionManager.class);
+ List<SubscriptionInfo> subscriptionInfoList =
+ subscriptionManager.getActiveSubscriptionInfoList();
+ loge("handleAlarmOrConfigChange ActiveSubscriptionInfoList = " + (
+ (subscriptionInfoList != null) ? subscriptionInfoList.size() : null));
+ for (SubscriptionInfo subInfo : subscriptionInfoList) {
+ if (mPhone.getSubId() != subInfo.getSubscriptionId()
+ && subInfo.getCarrierId() == mPhone.getCarrierId()) {
+ // We do not proceed to remove the Key from the DB as another slot contains
+ // same operator sim which is in active state.
+ loge("handleAlarmOrConfigChange same operator sim in another slot");
+ return true;
+ }
+ }
+ return false;
+ }
+
private void cleanupDownloadInfo() {
- Log.d(LOG_TAG, "Cleaning up download info");
+ logd("Cleaning up download info");
mDownloadId = -1;
- mMccMncForDownload = null;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mMccMncForDownload = "";
+ } else {
+ mMccMncForDownload = null;
+ }
mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
}
private void cleanupRenewalAlarms() {
- Log.d(LOG_TAG, "Cleaning up existing renewal alarms");
+ logd("Cleaning up existing renewal alarms");
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
Intent intent = new Intent(INTENT_KEY_RENEWAL_ALARM_PREFIX);
intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotIndex);
PendingIntent carrierKeyDownloadIntent = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- AlarmManager alarmManager =
- (AlarmManager) mContext.getSystemService(mContext.ALARM_SERVICE);
+ AlarmManager alarmManager =mContext.getSystemService(AlarmManager.class);
alarmManager.cancel(carrierKeyDownloadIntent);
}
@@ -331,7 +427,7 @@
cleanupRenewalAlarms();
int slotIndex = SubscriptionManager.getSlotIndex(mPhone.getSubId());
long minExpirationDate = getExpirationDate();
- Log.d(LOG_TAG, "minExpirationDate: " + new Date(minExpirationDate));
+ logd("minExpirationDate: " + new Date(minExpirationDate));
final AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE);
Intent intent = new Intent(INTENT_KEY_RENEWAL_ALARM_PREFIX);
@@ -339,16 +435,35 @@
PendingIntent carrierKeyDownloadIntent = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
alarmManager.set(AlarmManager.RTC_WAKEUP, minExpirationDate, carrierKeyDownloadIntent);
- Log.d(LOG_TAG, "setRenewalAlarm: action=" + intent.getAction() + " time="
+ logd("setRenewalAlarm: action=" + intent.getAction() + " time="
+ new Date(minExpirationDate));
}
/**
+ * Read the store the sim operetor value and update the value in case of change in the sim
+ * operetor.
+ */
+ public void updateSimOperator() {
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ String simOperator = mPhone.getOperatorNumeric();
+ if (!TextUtils.isEmpty(simOperator) && !simOperator.equals(mMccMncForDownload)) {
+ mMccMncForDownload = simOperator;
+ logd("updateSimOperator, Initialized mMccMncForDownload = " + mMccMncForDownload);
+ }
+ }
+ }
+
+ /**
* Returns the sim operator.
**/
@VisibleForTesting
public String getSimOperator() {
- return mTelephonyManager.getSimOperator(mPhone.getSubId());
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ updateSimOperator();
+ return mMccMncForDownload;
+ } else {
+ return mTelephonyManager.getSimOperator(mPhone.getSubId());
+ }
}
/**
@@ -356,7 +471,11 @@
**/
@VisibleForTesting
public int getSimCarrierId() {
- return mTelephonyManager.getSimCarrierId();
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ return (mCarrierId > 0) ? mCarrierId : mPhone.getCarrierId();
+ } else {
+ return mTelephonyManager.getSimCarrierId();
+ }
}
/**
@@ -367,7 +486,7 @@
@VisibleForTesting
public boolean isValidDownload(String currentMccMnc, long currentDownloadId, int carrierId) {
if (currentDownloadId != mDownloadId) {
- Log.e(LOG_TAG, "download ID=" + currentDownloadId
+ loge( "download ID=" + currentDownloadId
+ " for completed download does not match stored id=" + mDownloadId);
return false;
}
@@ -375,12 +494,12 @@
if (TextUtils.isEmpty(currentMccMnc) || TextUtils.isEmpty(mMccMncForDownload)
|| !TextUtils.equals(currentMccMnc, mMccMncForDownload)
|| mCarrierId != carrierId) {
- Log.e(LOG_TAG, "currentMccMnc=" + currentMccMnc + " storedMccMnc =" + mMccMncForDownload
+ loge( "currentMccMnc=" + currentMccMnc + " storedMccMnc =" + mMccMncForDownload
+ "currentCarrierId = " + carrierId + " storedCarrierId = " + mCarrierId);
return false;
}
- Log.d(LOG_TAG, "Matched MccMnc = " + currentMccMnc + ", carrierId = " + carrierId
+ logd("Matched MccMnc = " + currentMccMnc + ", carrierId = " + carrierId
+ ", downloadId: " + currentDownloadId);
return true;
}
@@ -390,7 +509,7 @@
**/
private void onDownloadComplete(long carrierKeyDownloadIdentifier, String mccMnc,
int carrierId) {
- Log.d(LOG_TAG, "onDownloadComplete: " + carrierKeyDownloadIdentifier);
+ logd("onDownloadComplete: " + carrierKeyDownloadIdentifier);
String jsonStr;
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(carrierKeyDownloadIdentifier);
@@ -405,22 +524,21 @@
try {
jsonStr = convertToString(mDownloadManager, carrierKeyDownloadIdentifier);
if (TextUtils.isEmpty(jsonStr)) {
- Log.d(LOG_TAG, "fallback to no gzip");
+ logd("fallback to no gzip");
jsonStr = convertToStringNoGZip(mDownloadManager,
carrierKeyDownloadIdentifier);
}
parseJsonAndPersistKey(jsonStr, mccMnc, carrierId);
} catch (Exception e) {
- Log.e(LOG_TAG, "Error in download:" + carrierKeyDownloadIdentifier
+ loge( "Error in download:" + carrierKeyDownloadIdentifier
+ ". " + e);
} finally {
mDownloadManager.remove(carrierKeyDownloadIdentifier);
}
}
- Log.d(LOG_TAG, "Completed downloading keys");
+ logd("Completed downloading keys");
}
cursor.close();
- return;
}
/**
@@ -442,7 +560,7 @@
CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING,
CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
} catch (RuntimeException e) {
- Log.e(LOG_TAG, "CarrierConfigLoader is not available.");
+ loge( "CarrierConfigLoader is not available.");
}
if (b == null || b.isEmpty()) {
return false;
@@ -452,10 +570,10 @@
mURL = b.getString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING);
mAllowedOverMeteredNetwork = b.getBoolean(
CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
+
if (mKeyAvailability == 0 || TextUtils.isEmpty(mURL)) {
- Log.d(LOG_TAG,
- "Carrier not enabled or invalid values. mKeyAvailability=" + mKeyAvailability
- + " mURL=" + mURL);
+ logd("Carrier not enabled or invalid values. mKeyAvailability=" + mKeyAvailability
+ + " mURL=" + mURL);
return false;
}
for (int key_type : CARRIER_KEY_TYPES) {
@@ -469,7 +587,7 @@
private static String convertToStringNoGZip(DownloadManager downloadManager, long downloadId) {
StringBuilder sb = new StringBuilder();
try (InputStream source = new FileInputStream(
- downloadManager.openDownloadedFile(downloadId).getFileDescriptor())) {
+ downloadManager.openDownloadedFile(downloadId).getFileDescriptor())) {
// If the carrier does not have the data gzipped, fallback to assuming it is not zipped.
// parseJsonAndPersistKey may still fail if the data is malformed, so we won't be
// persisting random bogus strings thinking it's the cert
@@ -488,8 +606,8 @@
private static String convertToString(DownloadManager downloadManager, long downloadId) {
try (InputStream source = new FileInputStream(
- downloadManager.openDownloadedFile(downloadId).getFileDescriptor());
- InputStream gzipIs = new GZIPInputStream(source)) {
+ downloadManager.openDownloadedFile(downloadId).getFileDescriptor());
+ InputStream gzipIs = new GZIPInputStream(source)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipIs, UTF_8));
StringBuilder sb = new StringBuilder();
@@ -523,7 +641,7 @@
public void parseJsonAndPersistKey(String jsonStr, String mccMnc, int carrierId) {
if (TextUtils.isEmpty(jsonStr) || TextUtils.isEmpty(mccMnc)
|| carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.e(LOG_TAG, "jsonStr or mcc, mnc: is empty or carrierId is UNKNOWN_CARRIER_ID");
+ loge( "jsonStr or mcc, mnc: is empty or carrierId is UNKNOWN_CARRIER_ID");
return;
}
try {
@@ -548,22 +666,28 @@
if (typeString.equals(JSON_TYPE_VALUE_EPDG)) {
type = TelephonyManager.KEY_TYPE_EPDG;
} else if (!typeString.equals(JSON_TYPE_VALUE_WLAN)) {
- Log.e(LOG_TAG, "Invalid key-type specified: " + typeString);
+ loge( "Invalid key-type specified: " + typeString);
}
}
String identifier = key.getString(JSON_IDENTIFIER);
Pair<PublicKey, Long> keyInfo =
getKeyInformation(cleanCertString(cert).getBytes());
if (mDeleteOldKeyAfterDownload) {
- mPhone.deleteCarrierInfoForImsiEncryption(TelephonyManager.UNKNOWN_CARRIER_ID);
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mPhone.deleteCarrierInfoForImsiEncryption(
+ TelephonyManager.UNKNOWN_CARRIER_ID, null);
+ } else {
+ mPhone.deleteCarrierInfoForImsiEncryption(
+ TelephonyManager.UNKNOWN_CARRIER_ID);
+ }
mDeleteOldKeyAfterDownload = false;
}
savePublicKey(keyInfo.first, type, identifier, keyInfo.second, mcc, mnc, carrierId);
}
} catch (final JSONException e) {
- Log.e(LOG_TAG, "Json parsing error: " + e.getMessage());
+ loge( "Json parsing error: " + e.getMessage());
} catch (final Exception e) {
- Log.e(LOG_TAG, "Exception getting certificate: " + e);
+ loge( "Exception getting certificate: " + e);
}
}
@@ -584,7 +708,7 @@
public static boolean isKeyEnabled(int keyType, int keyAvailability) {
// since keytype has values of 1, 2.... we need to subtract 1 from the keytype.
int returnValue = (keyAvailability >> (keyType - 1)) & 1;
- return (returnValue == 1) ? true : false;
+ return returnValue == 1;
}
/**
@@ -603,31 +727,42 @@
ImsiEncryptionInfo imsiEncryptionInfo =
mPhone.getCarrierInfoForImsiEncryption(key_type, false);
if (imsiEncryptionInfo == null) {
- Log.d(LOG_TAG, "Key not found for: " + key_type);
+ logd("Key not found for: " + key_type);
return true;
} else if (imsiEncryptionInfo.getCarrierId() == TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.d(LOG_TAG, "carrier key is unknown carrier, so prefer to reDownload");
+ logd("carrier key is unknown carrier, so prefer to reDownload");
mDeleteOldKeyAfterDownload = true;
return true;
}
Date imsiDate = imsiEncryptionInfo.getExpirationTime();
long timeToExpire = imsiDate.getTime() - System.currentTimeMillis();
- return (timeToExpire < START_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS) ? true : false;
+ return timeToExpire < START_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS;
}
return false;
}
private boolean downloadKey() {
- Log.d(LOG_TAG, "starting download from: " + mURL);
- String mccMnc = getSimOperator();
- int carrierId = getSimCarrierId();
- if (!TextUtils.isEmpty(mccMnc) || carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
- Log.d(LOG_TAG, "downloading key for mccmnc : " + mccMnc + ", carrierId : "
- + carrierId);
+ logd("starting download from: " + mURL);
+ String mccMnc = null;
+ int carrierId = -1;
+ if (Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ if (TextUtils.isEmpty(mMccMncForDownload)
+ || mCarrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
+ loge("mccmnc or carrierId is UnKnown");
+ return false;
+ }
} else {
- Log.e(LOG_TAG, "mccmnc or carrierId is UnKnown");
- return false;
+ mccMnc = getSimOperator();
+ carrierId = getSimCarrierId();
+ if (!TextUtils.isEmpty(mccMnc) || carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
+ Log.d(LOG_TAG, "downloading key for mccmnc : " + mccMnc + ", carrierId : "
+ + carrierId);
+ } else {
+ Log.e(LOG_TAG, "mccmnc or carrierId is UnKnown");
+ return false;
+ }
}
+
try {
// register the broadcast receiver to listen for download complete
IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
@@ -641,15 +776,16 @@
request.setAllowedOverMetered(mAllowedOverMeteredNetwork);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
request.addRequestHeader("Accept-Encoding", "gzip");
- Long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
-
- Log.d(LOG_TAG, "saving values mccmnc: " + mccMnc + ", downloadId: "
- + carrierKeyDownloadRequestId + ", carrierId: " + carrierId);
- mMccMncForDownload = mccMnc;
- mCarrierId = carrierId;
+ long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
+ if (!Flags.imsiKeyRetryDownloadOnPhoneUnlock()) {
+ mMccMncForDownload = mccMnc;
+ mCarrierId = carrierId;
+ }
mDownloadId = carrierKeyDownloadRequestId;
+ logd("saving values mccmnc: " + mMccMncForDownload + ", downloadId: "
+ + carrierKeyDownloadRequestId + ", carrierId: " + mCarrierId);
} catch (Exception e) {
- Log.e(LOG_TAG, "exception trying to download key from url: " + mURL + ", Exception = "
+ loge( "exception trying to download key from url: " + mURL + ", Exception = "
+ e.getMessage());
return false;
}
@@ -667,7 +803,7 @@
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
Pair<PublicKey, Long> keyInformation =
- new Pair(cert.getPublicKey(), cert.getNotAfter().getTime());
+ new Pair<>(cert.getPublicKey(), cert.getNotAfter().getTime());
return keyInformation;
}
@@ -699,4 +835,59 @@
cert.indexOf(CERT_BEGIN_STRING),
cert.indexOf(CERT_END_STRING) + CERT_END_STRING.length());
}
+
+ /**
+ * Registering the callback to listen on data connection availability.
+ *
+ * @param slotId Sim slotIndex that tries to download the key.
+ */
+ private void registerDefaultNetworkCb(int slotId) {
+ logd("RegisterDefaultNetworkCb for slotId = " + slotId);
+ if (mDefaultNetworkCallback == null
+ && slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ mDefaultNetworkCallback = new DefaultNetworkCallback(slotId);
+ mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
+ }
+ }
+
+ /**
+ * Unregister the data connection monitor listener.
+ */
+ private void unregisterDefaultNetworkCb(int slotId) {
+ logd("unregisterDefaultNetworkCb for slotId = " + slotId);
+ if (mDefaultNetworkCallback != null) {
+ mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
+ mDefaultNetworkCallback = null;
+ }
+ }
+
+ final class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback {
+ final int mSlotIndex;
+
+ public DefaultNetworkCallback(int slotId) {
+ mSlotIndex = slotId;
+ }
+
+ /** Called when the framework connects and has declared a new network ready for use. */
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ logd("Data network connected, slotId = " + mSlotIndex);
+ if (mConnectivityManager.getActiveNetwork() != null && SubscriptionManager.getSlotIndex(
+ mPhone.getSubId()) == mSlotIndex) {
+ mIsRequiredToHandleUnlock = false;
+ unregisterDefaultNetworkCb(mSlotIndex);
+ sendEmptyMessage(EVENT_NETWORK_AVAILABLE);
+ }
+ }
+ }
+
+ private void loge(String logStr) {
+ String TAG = LOG_TAG + " [" + mPhone.getPhoneId() + "]";
+ Log.e(TAG, logStr);
+ }
+
+ private void logd(String logStr) {
+ String TAG = LOG_TAG + " [" + mPhone.getPhoneId() + "]";
+ Log.d(TAG, logStr);
+ }
}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index db0fb2d..c4d9a17 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -411,7 +411,7 @@
mLinkBandwidthEstimator = mTelephonyComponentFactory
.inject(LinkBandwidthEstimator.class.getName())
- .makeLinkBandwidthEstimator(this);
+ .makeLinkBandwidthEstimator(this, getLooper());
mCallWaitingController = new CallWaitingController(this);
@@ -539,7 +539,7 @@
mContext.registerReceiver(mBroadcastReceiver, filter,
android.Manifest.permission.MODIFY_PHONE_STATE, null, Context.RECEIVER_EXPORTED);
- mCDM = new CarrierKeyDownloadManager(this, mFeatureFlags);
+ mCDM = new CarrierKeyDownloadManager(this);
mCIM = new CarrierInfoManager();
mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null);
@@ -2124,8 +2124,13 @@
@Override
public void deleteCarrierInfoForImsiEncryption(int carrierId) {
+ CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId(), carrierId);
+ }
+
+ @Override
+ public void deleteCarrierInfoForImsiEncryption(int carrierId, String simOperator) {
CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId(),
- carrierId);
+ carrierId, simOperator);
}
@Override
@@ -2298,6 +2303,11 @@
}
@Override
+ protected void onSetNetworkSelectionModeCompleted() {
+ mSST.pollState();
+ }
+
+ @Override
public String getCdmaPrlVersion() {
return mSST.getPrlVersion();
}
@@ -3669,6 +3679,7 @@
case EVENT_SUBSCRIPTIONS_CHANGED:
logd("EVENT_SUBSCRIPTIONS_CHANGED");
updateUsageSetting();
+ updateNullCipherNotifier();
break;
case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE:
logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE");
@@ -3769,7 +3780,8 @@
&& mNullCipherNotifier != null) {
ar = (AsyncResult) msg.obj;
SecurityAlgorithmUpdate update = (SecurityAlgorithmUpdate) ar.result;
- mNullCipherNotifier.onSecurityAlgorithmUpdate(mContext, getSubId(), update);
+ mNullCipherNotifier.onSecurityAlgorithmUpdate(mContext, getPhoneId(),
+ getSubId(), update);
}
break;
@@ -5444,6 +5456,25 @@
obtainMessage(EVENT_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED_DONE));
}
+ /**
+ * Update the phoneId -> subId mapping of the null cipher notifier.
+ */
+ @VisibleForTesting
+ public void updateNullCipherNotifier() {
+ if (!mFeatureFlags.enableModemCipherTransparencyUnsolEvents()) {
+ return;
+ }
+
+ SubscriptionInfoInternal subInfo = mSubscriptionManagerService
+ .getSubscriptionInfoInternal(getSubId());
+ boolean active = false;
+ if (subInfo != null) {
+ active = subInfo.isActive();
+ }
+ mNullCipherNotifier.setSubscriptionMapping(mContext, getPhoneId(),
+ active ? subInfo.getSubscriptionId() : -1);
+ }
+
@Override
public boolean isNullCipherAndIntegritySupported() {
return mIsNullCipherAndIntegritySupported;
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index 61cebbf..83d58af 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -18,6 +18,7 @@
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
+import static android.telephony.SubscriptionManager.TRANSFER_STATUS_CONVERTED;
import static android.telephony.TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE;
import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
@@ -159,6 +160,11 @@
/** The number of active modem count. */
private int mActiveModemCount;
+ private boolean mNeedSetDefaultVoice;
+ private boolean mNeedSetDefaultSms;
+ private boolean mNeedSetDefaultData;
+ private int mConvertedPsimSubId;
+
private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub";
private static class DataSettingsControllerCallback extends DataSettingsManagerCallback {
@@ -244,6 +250,8 @@
ccm.registerCarrierConfigChangeListener(this::post,
(slotIndex, subId, carrierId, specificCarrierId) ->
onCarrierConfigChanged(slotIndex, subId));
+
+ mConvertedPsimSubId = getConvertedPsimSubscriptionId();
}
private boolean hasCalling() {
@@ -404,6 +412,7 @@
if (DBG) log("onAllSubscriptionsLoaded: mSubInfoInitialized=" + mSubInfoInitialized);
if (!mSubInfoInitialized) {
mSubInfoInitialized = true;
+ mConvertedPsimSubId = getConvertedPsimSubscriptionId();
for (Phone phone : PhoneFactory.getPhones()) {
phone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
}
@@ -445,12 +454,13 @@
return;
}
- CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class);
- if (cm != null) {
- if (CarrierConfigManager.isConfigForIdentifiedCarrier(cm.getConfigForSubId(subId))) {
- mCarrierConfigLoadedSubIds[phoneId] = subId;
- reEvaluateAll();
- }
+ CarrierConfigManager cm;
+ if (!SubscriptionManager.isValidSubscriptionId(subId) // record SIM absent.
+ || ((cm = mContext.getSystemService(CarrierConfigManager.class)) != null
+ && CarrierConfigManager.isConfigForIdentifiedCarrier(
+ cm.getConfigForSubId(subId)))) {
+ mCarrierConfigLoadedSubIds[phoneId] = subId;
+ reEvaluateAll();
}
}
@@ -608,7 +618,6 @@
*/
protected void updateDefaults() {
if (DBG) log("updateDefaults");
-
if (!isReadyToReevaluate()) return;
List<SubscriptionInfo> activeSubInfos = mSubscriptionManagerService
@@ -687,7 +696,12 @@
// preference auto selection logic or display notification for end used to
// select voice/data/SMS preferences.
if (!autoFallbackEnabled) {
- sendSubChangeNotificationIfNeeded(change, dataSelected, voiceSelected, smsSelected);
+ // Hide the dialog for preferred SIM/data pick if the primary subscription change is
+ // due to the pSIM conversion.
+ if (!setDefaultForPsimConversionChanged(change, dataSelected, voiceSelected,
+ smsSelected)) {
+ sendSubChangeNotificationIfNeeded(change, dataSelected, voiceSelected, smsSelected);
+ }
} else {
updateUserPreferences(mPrimarySubList, dataSelected, voiceSelected, smsSelected);
}
@@ -803,6 +817,119 @@
}
}
+ /**
+ * Check that the primary subscription has changed due to the pSIM conversion.
+ * @param change Whether to update the mPrimarySubList.
+ * @param dataSelected Whether the default data subscription is updated
+ * @param voiceSelected Whether the default voice subscription is updated
+ * @param smsSelected Whether the default sms subscription is updated
+ * @return {@code true} if the primary subscription has changed due to the pSIM conversion,
+ * {@code false} otherwise.
+ */
+ private boolean setDefaultForPsimConversionChanged(int change, boolean dataSelected,
+ boolean voiceSelected, boolean smsSelected) {
+ if (!mFeatureFlags.supportPsimToEsimConversion()) {
+ log("pSIM to eSIM conversion is not supported");
+ return false;
+ }
+ if (mSubscriptionManagerService.isEsimBootStrapProvisioningActivated()) {
+ log("esim bootstrap activation in progress, skip notification");
+ return false;
+ }
+
+ @TelephonyManager.DefaultSubscriptionSelectType
+ int simSelectDialogType = getSimSelectDialogType(
+ change, dataSelected, voiceSelected, smsSelected);
+ SimCombinationWarningParams simCombinationParams = getSimCombinationWarningParams(change);
+ log("[setDefaultForPsimConversionChanged]showing dialog type:" + simSelectDialogType);
+ if (simSelectDialogType != EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE
+ || simCombinationParams.mWarningType != EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE) {
+ log("[setDefaultForPsimConversionChanged]Converted pSIM:" + mConvertedPsimSubId);
+ int subId = getConvertedPsimSubscriptionId();
+ if (subId != INVALID_SUBSCRIPTION_ID && subId != mConvertedPsimSubId) {
+ // If a primary subscription is removed and only one is left active, ask user
+ // for preferred sub selection if any default setting is not set.
+ if (simSelectDialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL) {
+ // check if pSIM's preference is voice.
+ if (mSubscriptionManagerService.getDefaultVoiceSubId()
+ == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ mNeedSetDefaultVoice = true;
+ }
+ // check if pSIM's preference is sms.
+ if (mSubscriptionManagerService.getDefaultSmsSubId()
+ == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ mNeedSetDefaultSms = true;
+ }
+ // check if pSIM's preference is data.
+ if (mSubscriptionManagerService.getDefaultDataSubId()
+ == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ mNeedSetDefaultData = true;
+ }
+ log("select type all, set preferred SIM :" + mPrimarySubList.get(0));
+ mSubscriptionManagerService.setDefaultVoiceSubId(mPrimarySubList.get(0));
+ mSubscriptionManagerService.setDefaultSmsSubId(mPrimarySubList.get(0));
+ mSubscriptionManagerService.setDefaultDataSubId(mPrimarySubList.get(0));
+ return true;
+ } else if (simSelectDialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA) {
+ // If another primary subscription is added or default data is not selected, ask
+ // user to select default for data as it's most important.
+ int newSubId = mPrimarySubList.get(0);
+ log("need to set voice:" + mNeedSetDefaultVoice
+ + ", sms:" + mNeedSetDefaultSms
+ + ", data:" + mNeedSetDefaultData);
+ // if the converted pSIM's preference is voice, set the default
+ // setting for the changed primary subscription to voice.
+ if (mNeedSetDefaultVoice) {
+ log("set preferred call, subId:" + newSubId);
+ mSubscriptionManagerService.setDefaultVoiceSubId(newSubId);
+ mNeedSetDefaultVoice = false;
+ }
+ // if the converted pSIM's preference is sms, set the default
+ // setting for the changed primary subscription to sms.
+ if (mNeedSetDefaultSms) {
+ log("set preferred sms, subId:" + newSubId);
+ mSubscriptionManagerService.setDefaultSmsSubId(newSubId);
+ mNeedSetDefaultSms = false;
+ }
+ // if the converted pSIM's preference is data, set the default
+ // setting for the changed primary subscription to data.
+ if (mNeedSetDefaultData) {
+ log("set preferred data, subId:" + newSubId);
+ mSubscriptionManagerService.setDefaultDataSubId(newSubId);
+ mNeedSetDefaultData = false;
+ }
+ mConvertedPsimSubId = subId;
+ log("set converted pSIM subId:" + mConvertedPsimSubId);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int getConvertedPsimSubscriptionId() {
+ // Check to see if any subscription has been converted due to the pSIM conversion.
+ // When the primary subscription is changed, if it is the same subscription as
+ // the previously converted subscription, it is not due to the pSIM conversion.
+ // So the dialog for preferred SIM/data pick should show.
+ // TODO(b/332261793): On Android W, we need to add CONVERTING status.
+ // The CONVERTING status allows us to determine if pSIM is in the process of converting,
+ // so we don't need to check for information about previously converted subscriptions.
+ int convertedSubId = INVALID_SUBSCRIPTION_ID;
+ if (mFeatureFlags.supportPsimToEsimConversion()) {
+ List<SubscriptionInfo> infos =
+ mSubscriptionManagerService.getAvailableSubscriptionInfoList(
+ mContext.getOpPackageName(), mContext.getAttributionTag());
+ for (SubscriptionInfo info : infos) {
+ if (!info.isEmbedded() && info.getTransferStatus() == TRANSFER_STATUS_CONVERTED) {
+ convertedSubId = info.getSubscriptionId();
+ }
+ }
+ }
+ log("getConvertedPsimSubscriptionId: convertedSubId=" + convertedSubId);
+ return convertedSubId;
+ }
+
private int getSimSelectDialogType(int change, boolean dataSelected,
boolean voiceSelected, boolean smsSelected) {
int dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE;
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index bf973e1..324e881 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -779,6 +779,7 @@
case EVENT_SET_NETWORK_MANUAL_COMPLETE:
case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
handleSetSelectNetwork((AsyncResult) msg.obj);
+ onSetNetworkSelectionModeCompleted();
return;
}
@@ -1536,6 +1537,12 @@
}
/**
+ * Called when setting network selection mode is complete.
+ */
+ protected void onSetNetworkSelectionModeCompleted() {
+ }
+
+ /**
* Query the radio for the current network selection mode.
*
* Return values:
@@ -4018,6 +4025,15 @@
return;
}
+ /**
+ * Deletes all the keys for a given Carrier from the device keystore.
+ * @param carrierId : the carrier ID which needs to be matched in the delete query
+ * @param simOperator : MccMnc which needs to be matched in the delete query.
+ */
+ public void deleteCarrierInfoForImsiEncryption(int carrierId, String simOperator) {
+
+ }
+
public int getCarrierId() {
return TelephonyManager.UNKNOWN_CARRIER_ID;
}
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index ef96d89..ffa5b69 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -45,6 +45,7 @@
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
@@ -97,7 +98,9 @@
private static PhoneConfigurationManager sInstance = null;
private final Context mContext;
- private PhoneCapability mStaticCapability;
+ // Static capability retrieved from the modem - may be null in the case where no info has been
+ // retrieved yet.
+ private PhoneCapability mStaticCapability = null;
private final Set<Integer> mSlotsSupportingSimultaneousCellularCalls = new HashSet<>(3);
private final Set<Integer> mSubIdsSupportingSimultaneousCellularCalls = new HashSet<>(3);
private final HashSet<Consumer<Set<Integer>>> mSimultaneousCellularCallingListeners =
@@ -151,8 +154,6 @@
mFeatureFlags = featureFlags;
// TODO: send commands to modem once interface is ready.
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- //initialize with default, it'll get updated when RADIO is ON/AVAILABLE
- mStaticCapability = getDefaultCapability();
mRadioConfig = RadioConfig.getInstance();
mHandler = new ConfigManagerHandler();
mPhoneStatusMap = new HashMap<>();
@@ -256,7 +257,8 @@
boolean halSupportSimulCalling = mRadioConfig != null
&& mRadioConfig.getRadioConfigProxy(null).getVersion().greaterOrEqual(
RIL.RADIO_HAL_VERSION_2_2)
- && getPhoneCount() > 1 && mStaticCapability.getMaxActiveVoiceSubscriptions() > 1;
+ && getPhoneCount() > 1
+ && getCellularStaticPhoneCapability().getMaxActiveVoiceSubscriptions() > 1;
// Register for simultaneous calling support changes in the modem if the HAL supports it
if (halSupportSimulCalling) {
updateSimultaneousCallingSupport();
@@ -318,7 +320,7 @@
log("Unable to add phoneStatus to cache. "
+ "No phone object provided for event " + msg.what);
}
- getStaticPhoneCapability();
+ updateRadioCapability();
break;
case EVENT_SWITCH_DSDS_CONFIG_DONE:
ar = (AsyncResult) msg.obj;
@@ -343,7 +345,7 @@
case EVENT_GET_PHONE_CAPABILITY_DONE:
ar = (AsyncResult) msg.obj;
if (ar != null && ar.exception == null) {
- mStaticCapability = (PhoneCapability) ar.result;
+ setStaticPhoneCapability((PhoneCapability) ar.result);
notifyCapabilityChanged();
for (Listener l : mListeners) {
l.onPhoneCapabilityChanged();
@@ -376,12 +378,12 @@
}
ar = (AsyncResult) msg.obj;
if (ar != null && ar.exception == null) {
- int[] returnedIntArray = (int[]) ar.result;
+ List<Integer> returnedArrayList = (List<Integer>) ar.result;
if (!mSlotsSupportingSimultaneousCellularCalls.isEmpty()) {
mSlotsSupportingSimultaneousCellularCalls.clear();
}
int maxValidPhoneSlot = getPhoneCount() - 1;
- for (int i : returnedIntArray) {
+ for (int i : returnedArrayList) {
if (i < 0 || i > maxValidPhoneSlot) {
loge("Invalid slot supporting DSDA =" + i + ". Disabling DSDA.");
mSlotsSupportingSimultaneousCellularCalls.clear();
@@ -534,21 +536,43 @@
}
/**
- * get static overall phone capabilities for all phones.
+ * @return static overall phone capabilities for all phones, including voice overrides.
*/
public synchronized PhoneCapability getStaticPhoneCapability() {
- if (getDefaultCapability().equals(mStaticCapability)) {
- log("getStaticPhoneCapability: sending the request for getting PhoneCapability");
- Message callback = Message.obtain(
- mHandler, EVENT_GET_PHONE_CAPABILITY_DONE);
- mRadioConfig.getPhoneCapability(callback);
- }
- mStaticCapability = maybeOverrideMaxActiveVoiceSubscriptions(mStaticCapability);
- log("getStaticPhoneCapability: mStaticCapability " + mStaticCapability);
+ boolean isDefault = mStaticCapability == null;
+ PhoneCapability caps = isDefault ? getDefaultCapability() : mStaticCapability;
+ caps = maybeOverrideMaxActiveVoiceSubscriptions(caps);
+ log("getStaticPhoneCapability: isDefault=" + isDefault + ", caps=" + caps);
+ return caps;
+ }
+
+ /**
+ * @return untouched capabilities returned from the modem
+ */
+ private synchronized PhoneCapability getCellularStaticPhoneCapability() {
+ log("getCellularStaticPhoneCapability: mStaticCapability " + mStaticCapability);
return mStaticCapability;
}
/**
+ * Caches the static PhoneCapability returned by the modem
+ */
+ public synchronized void setStaticPhoneCapability(PhoneCapability capability) {
+ log("setStaticPhoneCapability: mStaticCapability " + capability);
+ mStaticCapability = capability;
+ }
+
+ /**
+ * Query the modem to return its static PhoneCapability and cache it
+ */
+ @VisibleForTesting
+ public void updateRadioCapability() {
+ log("updateRadioCapability: sending the request for getting PhoneCapability");
+ Message callback = Message.obtain(mHandler, EVENT_GET_PHONE_CAPABILITY_DONE);
+ mRadioConfig.getPhoneCapability(callback);
+ }
+
+ /**
* get configuration related status of each phone.
*/
public PhoneCapability getCurrentPhoneCapability() {
@@ -556,12 +580,11 @@
}
public int getNumberOfModemsWithSimultaneousDataConnections() {
- return mStaticCapability.getMaxActiveDataSubscriptions();
+ return getStaticPhoneCapability().getMaxActiveDataSubscriptions();
}
public int getNumberOfModemsWithSimultaneousVoiceConnections() {
- return maybeOverrideMaxActiveVoiceSubscriptions(mStaticCapability)
- .getMaxActiveVoiceSubscriptions();
+ return getStaticPhoneCapability().getMaxActiveVoiceSubscriptions();
}
public boolean isVirtualDsdaEnabled() {
@@ -591,8 +614,7 @@
}
private void notifyCapabilityChanged() {
- mNotifier.notifyPhoneCapabilityChanged(maybeOverrideMaxActiveVoiceSubscriptions(
- mStaticCapability));
+ mNotifier.notifyPhoneCapabilityChanged(getStaticPhoneCapability());
}
/**
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index 803fb19..d9c5c9c 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -187,7 +187,7 @@
Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
sCommandsInterfaces[i] = new RIL(context,
RadioAccessFamily.getRafFromNetworkType(networkModes[i]),
- cdmaSubscription, i);
+ cdmaSubscription, i, featureFlags);
}
if (numPhones > 0) {
@@ -312,7 +312,7 @@
for (int i = prevActiveModemCount; i < activeModemCount; i++) {
sCommandsInterfaces[i] = new RIL(context, RadioAccessFamily.getRafFromNetworkType(
RILConstants.PREFERRED_NETWORK_MODE),
- cdmaSubscription, i);
+ cdmaSubscription, i, sFeatureFlags);
sPhones[i] = createPhone(context, i);
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY_IMS)) {
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index a65bfeb..073e242 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -33,6 +33,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.TelephonyServiceManager.ServiceRegisterer;
import android.telephony.ImsiEncryptionInfo;
import android.telephony.PhoneNumberUtils;
@@ -64,6 +65,7 @@
private AppOpsManager mAppOps;
private FeatureFlags mFeatureFlags;
private PackageManager mPackageManager;
+ private final int mVendorApiLevel;
public PhoneSubInfoController(Context context) {
this(context, new FeatureFlagsImpl());
@@ -80,6 +82,8 @@
mContext = context;
mPackageManager = context.getPackageManager();
mFeatureFlags = featureFlags;
+ mVendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
}
@Deprecated
@@ -799,7 +803,11 @@
if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
|| !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
- Binder.getCallingUserHandle())) {
+ Binder.getCallingUserHandle())
+ || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ // Skip to check associated telephony feature,
+ // if compatibility change is not enabled for the current process or
+ // the SDK version of vendor partition is less than Android V.
return;
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 86b4a60..b564961 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -88,6 +88,7 @@
import com.android.internal.telephony.cdma.CdmaInformationRecords;
import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
import com.android.internal.telephony.emergency.EmergencyConstants;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.imsphone.ImsCallInfo;
import com.android.internal.telephony.metrics.ModemRestartStats;
@@ -151,6 +152,15 @@
public static final HalVersion RADIO_HAL_VERSION_UNKNOWN = HalVersion.UNKNOWN;
/** @hide */
+ public static final HalVersion RADIO_HAL_VERSION_1_1 = new HalVersion(1, 1);
+
+ /** @hide */
+ public static final HalVersion RADIO_HAL_VERSION_1_2 = new HalVersion(1, 2);
+
+ /** @hide */
+ public static final HalVersion RADIO_HAL_VERSION_1_3 = new HalVersion(1, 3);
+
+ /** @hide */
public static final HalVersion RADIO_HAL_VERSION_1_4 = new HalVersion(1, 4);
/** @hide */
@@ -197,6 +207,8 @@
boolean mIsRadioProxyInitialized = false;
+ Boolean mIsRadioVersion20Cached = null;
+
// When we are testing emergency calls using ril.test.emergencynumber, this will trigger test
// ECbM when the call is ended.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -210,6 +222,8 @@
public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS;
+ @NonNull private final FeatureFlags mFeatureFlags;
+
/**
* An array of sets that records if services are disabled in the HAL for a specific phone ID
* slot to avoid further getService requests for that service. See XXX_SERVICE for the indices.
@@ -373,12 +387,27 @@
case EVENT_AIDL_PROXY_DEAD:
int aidlService = msg.arg1;
long msgCookie = (long) msg.obj;
- riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie
- + ", service = " + serviceToString(aidlService) + ", cookie = "
- + mServiceCookies.get(aidlService));
- if (msgCookie == mServiceCookies.get(aidlService).get()) {
- mIsRadioProxyInitialized = false;
- resetProxyAndRequestList(aidlService);
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ if (msgCookie == mServiceCookies.get(aidlService).get()) {
+ riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie
+ + ", service = " + serviceToString(aidlService) + ", cookie = "
+ + mServiceCookies.get(aidlService));
+ mIsRadioProxyInitialized = false;
+ resetProxyAndRequestList(aidlService);
+ // Remove duplicate death message to avoid duplicate reset.
+ mRilHandler.removeMessages(EVENT_AIDL_PROXY_DEAD);
+ } else {
+ riljLog("Ignore stale EVENT_AIDL_PROXY_DEAD for service "
+ + serviceToString(aidlService));
+ }
+ } else {
+ riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie
+ + ", service = " + serviceToString(aidlService) + ", cookie = "
+ + mServiceCookies.get(aidlService));
+ if (msgCookie == mServiceCookies.get(aidlService).get()) {
+ mIsRadioProxyInitialized = false;
+ resetProxyAndRequestList(aidlService);
+ }
}
break;
}
@@ -423,8 +452,14 @@
public void serviceDied(long cookie) {
// Deal with service going away
riljLog("serviceDied");
- mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
- HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie));
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage(
+ EVENT_RADIO_PROXY_DEAD,
+ HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie));
+ } else {
+ mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+ HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie));
+ }
}
}
@@ -456,24 +491,49 @@
@Override
public void binderDied() {
riljLog("Service " + serviceToString(mService) + " has died.");
- mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_AIDL_PROXY_DEAD, mService,
- 0 /* ignored arg2 */, mServiceCookies.get(mService).get()));
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage(
+ EVENT_AIDL_PROXY_DEAD, mService, 0 /* ignored arg2 */,
+ mServiceCookies.get(mService).get()));
+ } else {
+ mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_AIDL_PROXY_DEAD, mService,
+ 0 /* ignored arg2 */, mServiceCookies.get(mService).get()));
+ }
unlinkToDeath();
}
}
- private synchronized void resetProxyAndRequestList(int service) {
+ /**
+ * Reset services. If one of the AIDL service is reset, all the other AIDL services will be
+ * reset as well.
+ * @param service The service to reset.
+ */
+ private synchronized void resetProxyAndRequestList(@HalService int service) {
if (service == HAL_SERVICE_RADIO) {
mRadioProxy = null;
+ // Increment the cookie so that death notification can be ignored
+ mServiceCookies.get(service).incrementAndGet();
} else {
- mServiceProxies.get(service).clear();
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ // Reset all aidl services.
+ for (int i = MIN_SERVICE_IDX; i <= MAX_SERVICE_IDX; i++) {
+ if (i == HAL_SERVICE_RADIO) continue;
+ if (mServiceProxies.get(i) == null) {
+ // This should only happen in tests
+ riljLoge("Null service proxy for service " + serviceToString(i));
+ continue;
+ }
+ mServiceProxies.get(i).clear();
+ // Increment the cookie so that death notification can be ignored
+ mServiceCookies.get(i).incrementAndGet();
+ }
+ } else {
+ mServiceProxies.get(service).clear();
+ // Increment the cookie so that death notification can be ignored
+ mServiceCookies.get(service).incrementAndGet();
+ }
}
- // Increment the cookie so that death notification can be ignored
- mServiceCookies.get(service).incrementAndGet();
-
- // TODO: If a service doesn't exist or is unimplemented, it shouldn't cause the radio to
- // become unavailable for all other services
setRadioState(TelephonyManager.RADIO_POWER_UNAVAILABLE, true /* forceNotifyRegistrants */);
RILRequest.resetSerial();
@@ -483,7 +543,20 @@
if (service == HAL_SERVICE_RADIO) {
getRadioProxy();
} else {
- getRadioServiceProxy(service);
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ // Reset all aidl services.
+ for (int i = MIN_SERVICE_IDX; i <= MAX_SERVICE_IDX; i++) {
+ if (i == HAL_SERVICE_RADIO) continue;
+ if (mServiceProxies.get(i) == null) {
+ // This should only happen in tests
+ riljLoge("Null service proxy for service " + serviceToString(i));
+ continue;
+ }
+ getRadioServiceProxy(i);
+ }
+ } else {
+ getRadioServiceProxy(service);
+ }
}
}
@@ -501,10 +574,6 @@
mMockModem = null;
mMockModem = new MockModem(mContext, serviceName, mPhoneId);
- if (mMockModem == null) {
- riljLoge("MockModem create fail.");
- return false;
- }
// Disable HIDL service
if (mRadioProxy != null) {
@@ -541,8 +610,14 @@
if (serviceBound) {
mIsRadioProxyInitialized = false;
- for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
- resetProxyAndRequestList(service);
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ // Reset both hidl and aidl proxies.
+ resetProxyAndRequestList(HAL_SERVICE_RADIO);
+ resetProxyAndRequestList(HAL_SERVICE_DATA);
+ } else {
+ for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
+ resetProxyAndRequestList(service);
+ }
}
}
}
@@ -570,7 +645,15 @@
mHalVersion.put(service, RADIO_HAL_VERSION_UNSUPPORTED);
}
}
- resetProxyAndRequestList(service);
+ if (!mFeatureFlags.combineRilDeathHandle()) {
+ resetProxyAndRequestList(service);
+ }
+ }
+ if (mFeatureFlags.combineRilDeathHandle()) {
+ // Reset both hidl and aidl proxies. Must be after cleaning mocked halVersion,
+ // otherwise an aidl service will be incorrectly considered as disabled.
+ resetProxyAndRequestList(HAL_SERVICE_RADIO);
+ resetProxyAndRequestList(HAL_SERVICE_DATA);
}
}
}
@@ -982,16 +1065,33 @@
@Override
public synchronized void onSlotActiveStatusChange(boolean active) {
mIsRadioProxyInitialized = false;
- for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
+ if (mFeatureFlags.combineRilDeathHandle()) {
if (active) {
- // Try to connect to RIL services and set response functions.
- if (service == HAL_SERVICE_RADIO) {
- getRadioProxy();
- } else {
- getRadioServiceProxy(service);
+ for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
+ // Try to connect to RIL services and set response functions.
+ if (service == HAL_SERVICE_RADIO) {
+ getRadioProxy();
+ } else {
+ getRadioServiceProxy(service);
+ }
}
} else {
- resetProxyAndRequestList(service);
+ // Reset both hidl and aidl proxies
+ resetProxyAndRequestList(HAL_SERVICE_RADIO);
+ resetProxyAndRequestList(HAL_SERVICE_DATA);
+ }
+ } else {
+ for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
+ if (active) {
+ // Try to connect to RIL services and set response functions.
+ if (service == HAL_SERVICE_RADIO) {
+ getRadioProxy();
+ } else {
+ getRadioServiceProxy(service);
+ }
+ } else {
+ resetProxyAndRequestList(service);
+ }
}
}
}
@@ -999,19 +1099,16 @@
//***** Constructors
@UnsupportedAppUsage
- public RIL(Context context, int allowedNetworkTypes, int cdmaSubscription) {
- this(context, allowedNetworkTypes, cdmaSubscription, null);
- }
-
- @UnsupportedAppUsage
- public RIL(Context context, int allowedNetworkTypes, int cdmaSubscription, Integer instanceId) {
- this(context, allowedNetworkTypes, cdmaSubscription, instanceId, null);
+ public RIL(Context context, int allowedNetworkTypes, int cdmaSubscription, Integer instanceId,
+ @NonNull FeatureFlags flags) {
+ this(context, allowedNetworkTypes, cdmaSubscription, instanceId, null, flags);
}
@VisibleForTesting
public RIL(Context context, int allowedNetworkTypes, int cdmaSubscription, Integer instanceId,
- SparseArray<RadioServiceProxy> proxies) {
+ SparseArray<RadioServiceProxy> proxies, @NonNull FeatureFlags flags) {
super(context);
+ mFeatureFlags = flags;
if (RILJ_LOGD) {
riljLog("RIL: init allowedNetworkTypes=" + allowedNetworkTypes
+ " cdmaSubscription=" + cdmaSubscription + ")");
@@ -1118,7 +1215,7 @@
// Set radio callback; needed to set RadioIndication callback (should be done after
// wakelock stuff is initialized above as callbacks are received on separate binder threads)
for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) {
- if (!isRadioServiceSupported(service)) {
+ if (isRadioVersion2_0() && !isRadioServiceSupported(service)) {
riljLog("Not initializing " + serviceToString(service) + " (not supported)");
continue;
}
@@ -1140,12 +1237,13 @@
}
private boolean isRadioVersion2_0() {
+ if (mIsRadioVersion20Cached != null) return mIsRadioVersion20Cached;
for (int service = HAL_SERVICE_DATA; service <= MAX_SERVICE_IDX; service++) {
if (isRadioServiceSupported(service)) {
- return true;
+ return mIsRadioVersion20Cached = true;
}
}
- return false;
+ return mIsRadioVersion20Cached = false;
}
private boolean isRadioServiceSupported(int service) {
@@ -1286,17 +1384,6 @@
} else if (proxy instanceof RadioImsProxy) {
service = HAL_SERVICE_IMS;
}
-
- if (mHalVersion.get(service).less(version)) {
- riljLoge(String.format("%s not supported on service %s < %s.",
- request, serviceToString(service), version));
- if (result != null) {
- AsyncResult.forMessage(result, null,
- CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
- result.sendToTarget();
- }
- return false;
- }
if (proxy == null || proxy.isEmpty()) {
riljLoge(String.format("Unable to complete %s because service %s is not available.",
request, serviceToString(service)));
@@ -1307,6 +1394,16 @@
}
return false;
}
+ if (mHalVersion.get(service).less(version)) {
+ riljLoge(String.format("%s not supported on service %s < %s.",
+ request, serviceToString(service), version));
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return false;
+ }
return true;
}
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 13f6502..da20639 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -61,10 +61,6 @@
static final int EVENT_HIDL_SERVICE_DEAD = 1;
static final int EVENT_AIDL_SERVICE_DEAD = 2;
- static final HalVersion RADIO_CONFIG_HAL_VERSION_UNKNOWN = new HalVersion(-1, -1);
- static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1);
- static final HalVersion RADIO_CONFIG_HAL_VERSION_1_3 = new HalVersion(1, 3);
- static final HalVersion RADIO_CONFIG_HAL_VERSION_2_0 = new HalVersion(2, 0);
private final boolean mIsMobileNetworkSupported;
private final SparseArray<RILRequest> mRequestList = new SparseArray<>();
@@ -294,13 +290,12 @@
if (service != null) {
mRadioConfigProxy.setAidl(
- RADIO_CONFIG_HAL_VERSION_2_0,
android.hardware.radio.config.IRadioConfig.Stub.asInterface(service));
}
if (mRadioConfigProxy.isEmpty()) {
try {
- mRadioConfigProxy.setHidl(RADIO_CONFIG_HAL_VERSION_1_3,
+ mRadioConfigProxy.setHidl(RIL.RADIO_HAL_VERSION_1_3,
android.hardware.radio.config.V1_3.IRadioConfig.getService(true));
} catch (RemoteException | NoSuchElementException e) {
mRadioConfigProxy.clear();
@@ -310,7 +305,7 @@
if (mRadioConfigProxy.isEmpty()) {
try {
- mRadioConfigProxy.setHidl(RADIO_CONFIG_HAL_VERSION_1_1,
+ mRadioConfigProxy.setHidl(RIL.RADIO_HAL_VERSION_1_1,
android.hardware.radio.config.V1_1.IRadioConfig.getService(true));
} catch (RemoteException | NoSuchElementException e) {
mRadioConfigProxy.clear();
@@ -515,7 +510,7 @@
RadioConfigProxy proxy = getRadioConfigProxy(null);
if (proxy.isEmpty()) return;
- if (proxy.getVersion().less(RADIO_CONFIG_HAL_VERSION_1_1)) {
+ if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_1)) {
if (result != null) {
AsyncResult.forMessage(result, null,
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
@@ -543,7 +538,7 @@
*/
public boolean isSetPreferredDataCommandSupported() {
RadioConfigProxy proxy = getRadioConfigProxy(null);
- return !proxy.isEmpty() && proxy.getVersion().greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_1);
+ return !proxy.isEmpty() && proxy.getVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_1);
}
/**
@@ -574,7 +569,7 @@
RadioConfigProxy proxy = getRadioConfigProxy(result);
if (proxy.isEmpty()) return;
- if (proxy.getVersion().less(RADIO_CONFIG_HAL_VERSION_1_1)) {
+ if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_1)) {
if (result != null) {
AsyncResult.forMessage(
result, null, CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
@@ -628,7 +623,7 @@
RadioConfigProxy proxy = getRadioConfigProxy(Message.obtain(result));
if (proxy.isEmpty()) return;
- if (proxy.getVersion().less(RADIO_CONFIG_HAL_VERSION_1_3)) {
+ if (proxy.getVersion().less(RIL.RADIO_HAL_VERSION_1_3)) {
if (result != null) {
if (DBG) {
logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED");
diff --git a/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java b/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java
index 9aa1aaa..127631d 100644
--- a/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java
+++ b/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java
@@ -17,14 +17,14 @@
package com.android.internal.telephony;
import android.os.AsyncResult;
-import android.os.RemoteException;
import android.os.Trace;
import com.android.internal.telephony.uicc.IccSlotStatus;
import com.android.telephony.Rlog;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* This class is the AIDL implementation of IRadioConfigIndication interface.
@@ -58,9 +58,11 @@
*/
@Override
public void onSimultaneousCallingSupportChanged(int[] enabledLogicalSlots) {
- ArrayList<Integer> ret = RILUtils.primitiveArrayToArrayList(enabledLogicalSlots);
+ List<Integer> ret = (enabledLogicalSlots == null) ? Collections.emptyList() :
+ RILUtils.primitiveArrayToArrayList(enabledLogicalSlots);
logd("onSimultaneousCallingSupportChanged: enabledLogicalSlots = " + ret);
if (mRadioConfig.mSimultaneousCallingSupportStatusRegistrant != null) {
+ logd("onSimultaneousCallingSupportChanged: notifying registrant");
mRadioConfig.mSimultaneousCallingSupportStatusRegistrant.notifyRegistrant(
new AsyncResult(null, ret, null));
}
diff --git a/src/java/com/android/internal/telephony/RadioConfigProxy.java b/src/java/com/android/internal/telephony/RadioConfigProxy.java
index b6c6d68..9f34e29 100644
--- a/src/java/com/android/internal/telephony/RadioConfigProxy.java
+++ b/src/java/com/android/internal/telephony/RadioConfigProxy.java
@@ -31,14 +31,15 @@
* downstream users.
*/
public class RadioConfigProxy {
- private final HalVersion mRadioHalVersion;
+ private static final String TAG = "RadioConfigProxy";
+ private HalVersion mRadioHalVersion;
private final RadioConfigHidlServiceDeathRecipient mRadioConfigHidlServiceDeathRecipient;
private final RadioConfigAidlServiceDeathRecipient mRadioConfigAidlServiceDeathRecipient;
private volatile android.hardware.radio.config.V1_1.IRadioConfig mHidlRadioConfigProxy = null;
private volatile android.hardware.radio.config.IRadioConfig mAidlRadioConfigProxy = null;
- private HalVersion mRadioConfigHalVersion = RadioConfig.RADIO_CONFIG_HAL_VERSION_UNKNOWN;
+ private HalVersion mRadioConfigHalVersion = RIL.RADIO_HAL_VERSION_UNKNOWN;
private boolean mIsAidl;
public RadioConfigProxy(RadioConfig radioConfig, HalVersion radioHalVersion) {
@@ -83,13 +84,15 @@
/**
* Set IRadioConfig as the AIDL implementation for RadioConfigProxy
*
- * @param radioConfigHalVersion RadioConfig HAL version
* @param radioConfig IRadioConfig implementation
*/
- public void setAidl(
- HalVersion radioConfigHalVersion,
- android.hardware.radio.config.IRadioConfig radioConfig) {
- mRadioConfigHalVersion = radioConfigHalVersion;
+ public void setAidl(android.hardware.radio.config.IRadioConfig radioConfig) {
+ try {
+ mRadioConfigHalVersion = RIL.getServiceHalVersion(radioConfig.getInterfaceVersion());
+ Rlog.d(TAG, "setAidl: setting HAL version to version = " + mRadioConfigHalVersion);
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "setAidl: " + e);
+ }
mAidlRadioConfigProxy = radioConfig;
mIsAidl = true;
mRadioConfigAidlServiceDeathRecipient.setService(radioConfig.asBinder());
@@ -106,7 +109,7 @@
/** Reset RadioConfigProxy */
public void clear() {
- mRadioConfigHalVersion = RadioConfig.RADIO_CONFIG_HAL_VERSION_UNKNOWN;
+ mRadioConfigHalVersion = RIL.RADIO_HAL_VERSION_UNKNOWN;
mHidlRadioConfigProxy = null;
mAidlRadioConfigProxy = null;
mRadioConfigHidlServiceDeathRecipient.clear();
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index ba6479e..2a9bf7f 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -227,7 +227,6 @@
private final RegistrantList mAreaCodeChangedRegistrants = new RegistrantList();
/* Radio power off pending flag */
- // @GuardedBy("this")
private volatile boolean mPendingRadioPowerOffAfterDataOff = false;
/** Waiting period before recheck gprs and voice registration. */
@@ -3728,10 +3727,18 @@
// because operatorNumeric would be SIM's mcc/mnc when device is on IWLAN), but if the
// device has camped on a cell either to attempt registration or for emergency services,
// then for purposes of setting the locale, we don't care if registration fails or is
- // incomplete.
+ // incomplete. Additionally, if there is no cellular service and ims is registered over
+ // the IWLAN, the locale will not be updated.
// CellIdentity can return a null MCC and MNC in CDMA
String localeOperator = operatorNumeric;
- if (mSS.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_IWLAN) {
+ int dataNetworkType = mSS.getDataNetworkType();
+ if (dataNetworkType == TelephonyManager.NETWORK_TYPE_IWLAN
+ || (dataNetworkType == TelephonyManager.NETWORK_TYPE_UNKNOWN
+ && getImsRegistrationTech()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)) {
+ // TODO(b/333346537#comment10): Complete solution would be ignore mcc/mnc reported
+ // by the unsolicited indication OPERATOR from RIL, but only relies on MCC/MNC from
+ // data registration or voice registration.
localeOperator = null;
}
if (isInvalidOperatorNumeric(localeOperator)) {
@@ -5008,20 +5015,10 @@
}
/**
- * process the pending request to turn radio off after data is disconnected
- *
- * return true if there is pending request to process; false otherwise.
+ * return true if there is pending disconnect data request to process; false otherwise.
*/
- public boolean processPendingRadioPowerOffAfterDataOff() {
- synchronized(this) {
- if (mPendingRadioPowerOffAfterDataOff) {
- if (DBG) log("Process pending request to turn radio off.");
- hangupAndPowerOff();
- mPendingRadioPowerOffAfterDataOff = false;
- return true;
- }
- return false;
- }
+ public boolean isPendingRadioPowerOffAfterDataOff() {
+ return mPendingRadioPowerOffAfterDataOff;
}
private void onCarrierConfigurationChanged(int slotIndex) {
@@ -5911,4 +5908,17 @@
public @Nullable CellIdentity getLastKnownCellIdentity() {
return mLastKnownCellIdentity;
}
+
+ /**
+ * Get the tech where ims is currently registered.
+ * @return Returns the tech of ims registered. if not registered or no phome for ims, returns
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_NONE}.
+ */
+ private @ImsRegistrationImplBase.ImsRegistrationTech int getImsRegistrationTech() {
+ ImsPhone imsPhone = (ImsPhone) mPhone.getImsPhone();
+ if (imsPhone != null) {
+ return imsPhone.getImsRegistrationTech();
+ }
+ return ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
+ }
}
diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java
index b11d7e5..98f84b2 100644
--- a/src/java/com/android/internal/telephony/SignalStrengthController.java
+++ b/src/java/com/android/internal/telephony/SignalStrengthController.java
@@ -50,6 +50,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.util.ArrayUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;
@@ -60,6 +61,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
@@ -101,7 +103,7 @@
private static final int EVENT_GET_SIGNAL_STRENGTH = 6;
private static final int EVENT_POLL_SIGNAL_STRENGTH = 7;
private static final int EVENT_SIGNAL_STRENGTH_UPDATE = 8;
- private static final int EVENT_POLL_SIGNAL_STRENGTH_DONE = 9;
+ public static final int EVENT_POLL_SIGNAL_STRENGTH_DONE = 9;
private static final int EVENT_SERVICE_STATE_CHANGED = 10;
@NonNull
@@ -330,7 +332,7 @@
* @param signalStrength The new SignalStrength used for updating {@code mSignalStrength}.
*/
private void updateSignalStrength(@NonNull SignalStrength signalStrength) {
- mSignalStrength = signalStrength;
+ mSignalStrength = maybeOverrideSignalStrengthForTest(signalStrength);
ServiceStateTracker serviceStateTracker = mPhone.getServiceStateTracker();
if (serviceStateTracker != null) {
mSignalStrength.updateLevel(mCarrierConfig, serviceStateTracker.mSS);
@@ -342,6 +344,18 @@
}
/**
+ * For debug test build, override signal strength for testing.
+ * @param original The real signal strength to use if not in testing mode.
+ * @return The signal strength to broadcast to the external.
+ */
+ @NonNull private SignalStrength maybeOverrideSignalStrengthForTest(
+ @NonNull SignalStrength original) {
+ return TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null
+ ? Objects.requireNonNullElse(mPhone.getTelephonyTester()
+ .getOverriddenSignalStrength(), original) : original;
+ }
+
+ /**
* @return signal strength
*/
@NonNull
@@ -750,7 +764,7 @@
}
void setSignalStrengthDefaultValues() {
- mSignalStrength = new SignalStrength();
+ mSignalStrength = maybeOverrideSignalStrengthForTest(new SignalStrength());
mSignalStrengthUpdatedTime = System.currentTimeMillis();
}
diff --git a/src/java/com/android/internal/telephony/SimultaneousCallingTracker.java b/src/java/com/android/internal/telephony/SimultaneousCallingTracker.java
index 0a14ccd..0b427f8 100644
--- a/src/java/com/android/internal/telephony/SimultaneousCallingTracker.java
+++ b/src/java/com/android/internal/telephony/SimultaneousCallingTracker.java
@@ -494,7 +494,7 @@
l.onSimultaneousCallingSupportChanged(simultaneousCallSubscriptionIdMap);
}
} catch (Exception e) {
- Log.w(LOG_TAG, "handleVideoCapabilitiesChanged: Exception = " + e);
+ Log.w(LOG_TAG, "handleSimultaneousCallingSupportChanged: Exception = " + e);
}
}
diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java
index da1b07a..59184d8 100644
--- a/src/java/com/android/internal/telephony/SmsController.java
+++ b/src/java/com/android/internal/telephony/SmsController.java
@@ -38,6 +38,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.os.TelephonyServiceManager.ServiceRegisterer;
import android.os.UserHandle;
import android.provider.Telephony.Sms.Intents;
@@ -70,6 +71,8 @@
private final Context mContext;
private final PackageManager mPackageManager;
+ private final int mVendorApiLevel;
+
@NonNull private final FeatureFlags mFlags;
@VisibleForTesting
@@ -83,6 +86,9 @@
if (smsServiceRegisterer.get() == null) {
smsServiceRegisterer.register(this);
}
+
+ mVendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
}
private Phone getPhone(int subId) {
@@ -296,16 +302,17 @@
SubscriptionInfo info;
try {
info = getSubscriptionInfo(subId);
+
+ if (isBluetoothSubscription(info)) {
+ sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent);
+ } else {
+ sendIccText(subId, callingPackage, destAddr, scAddr, text, sentIntent,
+ deliveryIntent, persistMessageForNonDefaultSmsApp, messageId,
+ skipShortCodeCheck);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
-
- if (isBluetoothSubscription(info)) {
- sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent);
- } else {
- sendIccText(subId, callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
- persistMessageForNonDefaultSmsApp, messageId, skipShortCodeCheck);
- }
}
private boolean isBluetoothSubscription(SubscriptionInfo info) {
@@ -1224,7 +1231,11 @@
if (!mFlags.enforceTelephonyFeatureMappingForPublicApis()
|| !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
- Binder.getCallingUserHandle())) {
+ Binder.getCallingUserHandle())
+ || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ // Skip to check associated telephony feature,
+ // if compatibility change is not enabled for the current process or
+ // the SDK version of vendor partition is less than Android V.
return;
}
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 5da4b12..0b0f9d3 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -523,8 +523,8 @@
/**
* Create a new LinkBandwidthEstimator.
*/
- public LinkBandwidthEstimator makeLinkBandwidthEstimator(Phone phone) {
- return new LinkBandwidthEstimator(phone, mTelephonyFacade);
+ public LinkBandwidthEstimator makeLinkBandwidthEstimator(Phone phone, Looper looper) {
+ return new LinkBandwidthEstimator(phone, looper, mTelephonyFacade);
}
/**
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
index b9e04c8..7d3d75d 100644
--- a/src/java/com/android/internal/telephony/TelephonyTester.java
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -17,16 +17,21 @@
package com.android.internal.telephony;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
+import android.os.AsyncResult;
import android.os.BadParcelableException;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.telephony.AccessNetworkConstants;
+import android.telephony.CellSignalStrengthLte;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsConferenceState;
@@ -46,6 +51,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -163,6 +169,7 @@
private static List<ImsExternalCallState> mImsExternalCallStates = null;
private Intent mServiceStateTestIntent;
+ private SignalStrengthTestable mSignalStrengthTest;
private Phone mPhone;
@@ -386,11 +393,68 @@
}
/**
+ * Testable signal strength that mocks its fields.
+ */
+ private class SignalStrengthTestable extends SignalStrength {
+ private SignalStrengthTestable() {
+ super();
+ }
+
+ public void mockLevel(int level) {
+ try {
+ Field lteField = SignalStrength.class.getDeclaredField("mLte");
+ lteField.setAccessible(true);
+ CellSignalStrengthLte lte = (CellSignalStrengthLte) lteField.get(this);
+
+ Field lvlField = CellSignalStrengthLte.class.getDeclaredField("mLevel");
+ lvlField.setAccessible(true);
+ lvlField.set(lte, level);
+ } catch (Exception e) {
+ log("SignalStrengthTestable: mockLevel " + e);
+ }
+ }
+
+ @Override
+ public void updateLevel(PersistableBundle cc, ServiceState ss) {
+ log("SignalStrengthTestable: updateLevel: do nothing ");
+ }
+
+ @Override
+ public String toString() {
+ return "SignalStrengthTestable-" + getLevel();
+ }
+ }
+
+ /** {@link android.telephony.SignalStrength} */
+ public void setSignalStrength(int level) {
+ if (level > -1) {
+ log("setSignalStrength: level " + level);
+ mSignalStrengthTest = new SignalStrengthTestable();
+ mSignalStrengthTest.mockLevel(level);
+ AsyncResult ar = new AsyncResult(null, mSignalStrengthTest, null);
+ mPhone.getSignalStrengthController().sendMessage(mPhone.getSignalStrengthController()
+ .obtainMessage(SignalStrengthController.EVENT_POLL_SIGNAL_STRENGTH_DONE, ar));
+ } else {
+ log("setSignalStrength: clear mock");
+ mSignalStrengthTest = null;
+ mPhone.getSignalStrengthController().getSignalStrengthFromCi();
+ }
+ }
+
+ /** {@link android.telephony.SignalStrength} */
+ @Nullable
+ public SignalStrength getOverriddenSignalStrength() {
+ return mSignalStrengthTest;
+ }
+
+ /**
* Set the service state test intent.
*
* @param intent The service state test intent.
*/
public void setServiceStateTestIntent(@NonNull Intent intent) {
+ // Don't process if the intent is not prepared for this phone slot.
+ if (mPhone.getPhoneId() != intent.getIntExtra(EXTRA_PHONE_ID, mPhone.getPhoneId())) return;
mServiceStateTestIntent = intent;
// Trigger the service state update. The replacement will be done in
// overrideServiceState().
@@ -400,10 +464,6 @@
void overrideServiceState(ServiceState ss) {
if (mServiceStateTestIntent == null || ss == null) return;
- if (mPhone.getPhoneId() != mServiceStateTestIntent.getIntExtra(
- EXTRA_PHONE_ID, mPhone.getPhoneId())) {
- return;
- }
if (mServiceStateTestIntent.hasExtra(EXTRA_ACTION)
&& ACTION_RESET.equals(mServiceStateTestIntent.getStringExtra(EXTRA_ACTION))) {
log("Service state override reset");
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index 7742ca1..4da1622 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -284,10 +284,12 @@
CatLog.d(this, "Disposing CatService object");
mIccRecords.unregisterForRecordsLoaded(this);
- try {
- mContext.unregisterReceiver(mSmsBroadcastReceiver);
- } catch (IllegalArgumentException e) {
- CatLog.e(this, "mSmsBroadcastReceiver: was not registered" + e);
+ if (sFlags.unregisterSmsBroadcastReceiverFromCatService()) {
+ try {
+ mContext.unregisterReceiver(mSmsBroadcastReceiver);
+ } catch (IllegalArgumentException e) {
+ CatLog.e(this, "mSmsBroadcastReceiver: was not registered" + e);
+ }
}
// Clean up stk icon if dispose is called
diff --git a/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
index 85d5a35..85413f5 100644
--- a/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
+++ b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
@@ -27,6 +27,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.satellite.SatelliteConfig;
import com.android.internal.telephony.satellite.SatelliteConfigParser;
+import com.android.internal.telephony.satellite.SatelliteConstants;
+import com.android.internal.telephony.satellite.metrics.ConfigUpdaterMetricsStats;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.server.updates.ConfigUpdateInstallReceiver;
@@ -57,6 +59,7 @@
private final Object mConfigParserLock = new Object();
@GuardedBy("mConfigParserLock")
private ConfigParser mConfigParser;
+ @NonNull private final ConfigUpdaterMetricsStats mConfigUpdaterMetricsStats;
public static TelephonyConfigUpdateInstallReceiver sReceiverAdaptorInstance =
@@ -72,6 +75,7 @@
public TelephonyConfigUpdateInstallReceiver() {
super(UPDATE_DIR, NEW_CONFIG_CONTENT_PATH, UPDATE_METADATA_PATH, VERSION);
+ mConfigUpdaterMetricsStats = ConfigUpdaterMetricsStats.getOrCreateInstance();
}
/**
@@ -97,6 +101,8 @@
SatelliteConfig satelliteConfig = (SatelliteConfig) parser.getConfig();
if (satelliteConfig == null) {
Log.e(TAG, "satelliteConfig is null");
+ mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA);
return false;
}
@@ -109,12 +115,16 @@
for (String plmn : plmns) {
if (!TelephonyUtils.isValidPlmn(plmn)) {
Log.e(TAG, "found invalid plmn : " + plmn);
+ mConfigUpdaterMetricsStats.reportCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_PLMN);
return false;
}
Set<Integer> serviceSet = plmnsServices.get(plmn);
for (int service : serviceSet) {
if (!TelephonyUtils.isValidService(service)) {
Log.e(TAG, "found invalid service : " + service);
+ mConfigUpdaterMetricsStats.reportCarrierConfigError(SatelliteConstants
+ .CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_SUPPORTED_SERVICES);
return false;
}
}
@@ -149,8 +159,11 @@
int previousVersion = getInstance().mConfigParser.mVersion;
Log.d(TAG, "previous version is " + previousVersion + " | updated version is "
+ updatedVersion);
+ mConfigUpdaterMetricsStats.setConfigVersion(updatedVersion);
if (updatedVersion <= previousVersion) {
Log.e(TAG, "updatedVersion is smaller than previousVersion");
+ mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_INVALID_VERSION);
return;
}
}
@@ -167,6 +180,8 @@
if (!copySourceFileToTargetFile(NEW_CONFIG_CONTENT_PATH, VALID_CONFIG_CONTENT_PATH)) {
Log.e(TAG, "fail to copy to the valid satellite carrier config data");
+ mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR);
}
}
@@ -231,6 +246,8 @@
public ConfigParser getNewConfigParser(String domain, @Nullable byte[] data) {
if (data == null) {
Log.d(TAG, "content data is null");
+ mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_NO_DATA);
return null;
}
switch (domain) {
@@ -238,6 +255,8 @@
return new SatelliteConfigParser(data);
default:
Log.e(TAG, "DOMAIN should be specified");
+ mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError(
+ SatelliteConstants.CONFIG_UPDATE_RESULT_INVALID_DOMAIN);
return null;
}
}
diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java
index 3d3fbe9..1d720ac 100644
--- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java
+++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java
@@ -69,7 +69,6 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
@@ -86,7 +85,8 @@
/**
* The counters to detect frequent QNS attempt to change preferred network transport by ApnType.
*/
- private final @NonNull SparseArray<SlidingWindowEventCounter> mApnTypeToQnsChangeNetworkCounter;
+ @NonNull
+ private final SparseArray<SlidingWindowEventCounter> mApnTypeToQnsChangeNetworkCounter;
private final String mLogTag;
private final LocalLog mLocalLog = new LocalLog(64);
@@ -109,12 +109,11 @@
private final CarrierConfigManager mCarrierConfigManager;
- private @Nullable DataConfigManager mDataConfigManager;
+ @Nullable
+ private DataConfigManager mDataConfigManager;
private IQualifiedNetworksService mIQualifiedNetworksService;
- private AccessNetworksManagerDeathRecipient mDeathRecipient;
-
private String mTargetBindingPackageName;
private QualifiedNetworksServiceConnection mServiceConnection;
@@ -122,7 +121,8 @@
// Available networks. Key is the APN type.
private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>();
- private final @TransportType int[] mAvailableTransports;
+ @TransportType
+ private final int[] mAvailableTransports;
private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList();
@@ -135,7 +135,8 @@
/**
* Callbacks for passing information to interested clients.
*/
- private final @NonNull Set<AccessNetworksManagerCallback> mAccessNetworksManagerCallbacks =
+ @NonNull
+ private final Set<AccessNetworksManagerCallback> mAccessNetworksManagerCallbacks =
new ArraySet<>();
private final FeatureFlags mFeatureFlags;
@@ -144,7 +145,8 @@
* Represents qualified network types list on a specific APN type.
*/
public static class QualifiedNetworks {
- public final @ApnType int apnType;
+ @ApnType
+ public final int apnType;
// The qualified networks in preferred order. Each network is a AccessNetworkType.
public final @NonNull @RadioAccessNetworkType int[] qualifiedNetworks;
public QualifiedNetworks(@ApnType int apnType, @NonNull int[] qualifiedNetworks) {
@@ -198,11 +200,12 @@
public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) log("onServiceConnected " + name);
mIQualifiedNetworksService = IQualifiedNetworksService.Stub.asInterface(service);
- mDeathRecipient = new AccessNetworksManagerDeathRecipient();
+ AccessNetworksManagerDeathRecipient deathRecipient =
+ new AccessNetworksManagerDeathRecipient();
mLastBoundPackageName = getQualifiedNetworksServicePackageName();
try {
- service.linkToDeath(mDeathRecipient, 0 /* flags */);
+ service.linkToDeath(deathRecipient, 0 /* flags */);
mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(),
new QualifiedNetworksServiceCallback());
} catch (RemoteException e) {
@@ -328,27 +331,22 @@
log("onNetworkValidationRequested: networkCapability = ["
+ DataUtils.networkCapabilityToString(networkCapability) + "]");
- dnc.requestNetworkValidation(networkCapability, new Consumer<Integer>() {
- @Override
- public void accept(Integer result) {
- post(() -> {
- try {
- log("onNetworkValidationRequestDone:"
- + DataServiceCallback.resultCodeToString(result));
- resultCodeCallback.accept(result.intValue());
- } catch (RemoteException e) {
- // Ignore if the remote process is no longer available to call back.
- loge("onNetworkValidationRequestDone RemoteException" + e);
- }
- });
+ dnc.requestNetworkValidation(networkCapability, result -> post(() -> {
+ try {
+ log("onNetworkValidationRequestDone:"
+ + DataServiceCallback.resultCodeToString(result));
+ resultCodeCallback.accept(result);
+ } catch (RemoteException e) {
+ // Ignore if the remote process is no longer available to call back.
+ loge("onNetworkValidationRequestDone RemoteException" + e);
}
- });
+ }));
}
@Override
- public void onReconnectQualifedNetworkType(int apnTypes, int qualifiedNetworkType) {
+ public void onReconnectQualifiedNetworkType(int apnTypes, int qualifiedNetworkType) {
if (mFeatureFlags.reconnectQualifiedNetwork()) {
- log("onReconnectQualifedNetworkType: apnTypes = ["
+ log("onReconnectQualifiedNetworkType: apnTypes = ["
+ ApnSetting.getApnTypesStringFromBitmask(apnTypes)
+ "], networks = [" + AccessNetworkType.toString(qualifiedNetworkType)
+ "]");
diff --git a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
index 343bb0b..10371ab 100644
--- a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
+++ b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java
@@ -137,17 +137,26 @@
private static final long RETRY_LONG_DELAY_TIMER_THRESHOLD_MILLIS = TimeUnit
.MINUTES.toMillis(1);
- private final @NonNull LocalLog mLocalLog = new LocalLog(128);
- private final @NonNull Context mContext;
- private static @NonNull FeatureFlags sFeatureFlags = new FeatureFlagsImpl();
- private final @NonNull SubscriptionManagerService mSubscriptionManagerService;
- private final @NonNull PhoneSwitcher mPhoneSwitcher;
- private final @NonNull AutoDataSwitchControllerCallback mPhoneSwitcherCallback;
- private final @NonNull AlarmManager mAlarmManager;
+ @NonNull
+ private final LocalLog mLocalLog = new LocalLog(128);
+ @NonNull
+ private final Context mContext;
+ @NonNull
+ private static FeatureFlags sFeatureFlags = new FeatureFlagsImpl();
+ @NonNull
+ private final SubscriptionManagerService mSubscriptionManagerService;
+ @NonNull
+ private final PhoneSwitcher mPhoneSwitcher;
+ @NonNull
+ private final AutoDataSwitchControllerCallback mPhoneSwitcherCallback;
+ @NonNull
+ private final AlarmManager mAlarmManager;
/** A map of a scheduled event to its associated extra for action when the event fires off. */
- private final @NonNull Map<Integer, Object> mScheduledEventsToExtras;
+ @NonNull
+ private final Map<Integer, Object> mScheduledEventsToExtras;
/** A map of an event to its associated alarm listener callback for when the event fires off. */
- private final @NonNull Map<Integer, AlarmManager.OnAlarmListener> mEventsToAlarmListener;
+ @NonNull
+ private final Map<Integer, AlarmManager.OnAlarmListener> mEventsToAlarmListener;
/**
* Event extras for checking environment stability.
* @param targetPhoneId The target phone Id to switch to when the stability check pass.
@@ -193,7 +202,7 @@
* To indicate whether allow using roaming nDDS if user enabled its roaming when the DDS is not
* usable(OOS or disabled roaming)
*/
- private boolean mAllowNddsRoamning = true;
+ private boolean mAllowNddsRoaming = true;
/** The count of consecutive auto switch validation failure **/
private int mAutoSwitchValidationFailedCount = 0;
/**
@@ -202,7 +211,8 @@
private int mAutoDataSwitchValidationMaxRetry;
/** The signal status of phones, where index corresponds to phone Id. */
- private @NonNull PhoneSignalStatus[] mPhonesSignalStatus;
+ @NonNull
+ private PhoneSignalStatus[] mPhonesSignalStatus;
/**
* The phone Id of the pending switching phone. Used for pruning frequent switch evaluation.
*/
@@ -268,23 +278,24 @@
boolean isUsingNonTerrestrialNetwork = sFeatureFlags.carrierEnabledSatelliteFlag()
&& (serviceState != null) && serviceState.isUsingNonTerrestrialNetwork();
- switch (mDataRegState) {
- case NetworkRegistrationInfo.REGISTRATION_STATE_HOME:
+ return switch (mDataRegState) {
+ case NetworkRegistrationInfo.REGISTRATION_STATE_HOME -> {
if (isUsingNonTerrestrialNetwork) {
- return UsableState.NON_TERRESTRIAL;
+ yield UsableState.NON_TERRESTRIAL;
}
- return UsableState.HOME;
- case NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING:
+ yield UsableState.HOME;
+ }
+ case NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING -> {
if (mPhone.getDataRoamingEnabled()) {
if (isUsingNonTerrestrialNetwork) {
- return UsableState.NON_TERRESTRIAL;
+ yield UsableState.NON_TERRESTRIAL;
}
- return UsableState.ROAMING_ENABLED;
+ yield UsableState.ROAMING_ENABLED;
}
- return UsableState.NOT_USABLE;
- default:
- return UsableState.NOT_USABLE;
- }
+ yield UsableState.NOT_USABLE;
+ }
+ default -> UsableState.NOT_USABLE;
+ };
}
@Override
@@ -450,7 +461,7 @@
DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager();
mScoreTolerance = dataConfig.getAutoDataSwitchScoreTolerance();
mRequirePingTestBeforeSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired();
- mAllowNddsRoamning = dataConfig.doesAutoDataSwitchAllowRoaming();
+ mAllowNddsRoaming = dataConfig.doesAutoDataSwitchAllowRoaming();
mAutoDataSwitchAvailabilityStabilityTimeThreshold =
dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold();
mAutoDataSwitchPerformanceStabilityTimeThreshold =
@@ -929,7 +940,7 @@
* @return {@code true} If the feature of switching to roaming non DDS is enabled.
*/
private boolean isNddsRoamingEnabled() {
- return sFeatureFlags.autoDataSwitchAllowRoaming() && mAllowNddsRoamning;
+ return sFeatureFlags.autoDataSwitchAllowRoaming() && mAllowNddsRoaming;
}
/**
@@ -1012,19 +1023,20 @@
}
/** Auto data switch evaluation reason to string. */
- public static @NonNull String evaluationReasonToString(
+ @NonNull
+ public static String evaluationReasonToString(
@AutoDataSwitchEvaluationReason int reason) {
- switch (reason) {
- case EVALUATION_REASON_REGISTRATION_STATE_CHANGED: return "REGISTRATION_STATE_CHANGED";
- case EVALUATION_REASON_DISPLAY_INFO_CHANGED: return "DISPLAY_INFO_CHANGED";
- case EVALUATION_REASON_SIGNAL_STRENGTH_CHANGED: return "SIGNAL_STRENGTH_CHANGED";
- case EVALUATION_REASON_DEFAULT_NETWORK_CHANGED: return "DEFAULT_NETWORK_CHANGED";
- case EVALUATION_REASON_DATA_SETTINGS_CHANGED: return "DATA_SETTINGS_CHANGED";
- case EVALUATION_REASON_RETRY_VALIDATION: return "RETRY_VALIDATION";
- case EVALUATION_REASON_SIM_LOADED: return "SIM_LOADED";
- case EVALUATION_REASON_VOICE_CALL_END: return "VOICE_CALL_END";
- }
- return "Unknown(" + reason + ")";
+ return switch (reason) {
+ case EVALUATION_REASON_REGISTRATION_STATE_CHANGED -> "REGISTRATION_STATE_CHANGED";
+ case EVALUATION_REASON_DISPLAY_INFO_CHANGED -> "DISPLAY_INFO_CHANGED";
+ case EVALUATION_REASON_SIGNAL_STRENGTH_CHANGED -> "SIGNAL_STRENGTH_CHANGED";
+ case EVALUATION_REASON_DEFAULT_NETWORK_CHANGED -> "DEFAULT_NETWORK_CHANGED";
+ case EVALUATION_REASON_DATA_SETTINGS_CHANGED -> "DATA_SETTINGS_CHANGED";
+ case EVALUATION_REASON_RETRY_VALIDATION -> "RETRY_VALIDATION";
+ case EVALUATION_REASON_SIM_LOADED -> "SIM_LOADED";
+ case EVALUATION_REASON_VOICE_CALL_END -> "VOICE_CALL_END";
+ default -> "Unknown(" + reason + ")";
+ };
}
/** @return {@code true} if the sub is active. */
@@ -1085,8 +1097,9 @@
* @param isDueToAutoSwitch {@code true} if the switch was due to auto data switch feature.
*/
public void displayAutoDataSwitchNotification(int phoneId, boolean isDueToAutoSwitch) {
- NotificationManager notificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ NotificationManager notificationManager = mContext.getSystemService(
+ NotificationManager.class);
+ if (notificationManager == null) return;
if (mDisplayedNotification) {
// cancel posted notification if any exist
notificationManager.cancel(AUTO_DATA_SWITCH_NOTIFICATION_TAG,
diff --git a/src/java/com/android/internal/telephony/data/CellularDataService.java b/src/java/com/android/internal/telephony/data/CellularDataService.java
index 80d6b53..a75d4df 100644
--- a/src/java/com/android/internal/telephony/data/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/data/CellularDataService.java
@@ -18,6 +18,7 @@
import static android.telephony.data.DataServiceCallback.RESULT_SUCCESS;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkProperties;
import android.os.AsyncResult;
@@ -41,6 +42,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* This class represents cellular data service which handles telephony data requests and response
@@ -61,6 +63,7 @@
private static final int CANCEL_HANDOVER = 8;
private static final int APN_UNTHROTTLED = 9;
+ @SuppressWarnings("unchecked")
private class CellularDataServiceProvider extends DataService.DataServiceProvider {
private final Map<Message, DataServiceCallback> mCallbackMap = new HashMap<>();
@@ -69,14 +72,15 @@
private final Phone mPhone;
+ @SuppressWarnings("unchecked")
private CellularDataServiceProvider(int slotId) {
super(slotId);
mPhone = PhoneFactory.getPhone(getSlotIndex());
- mHandler = new Handler(Looper.myLooper()) {
+ mHandler = new Handler(Objects.requireNonNull(Looper.myLooper())) {
@Override
- public void handleMessage(Message message) {
+ public void handleMessage(@NonNull Message message) {
DataServiceCallback callback = mCallbackMap.remove(message);
AsyncResult ar = (AsyncResult) message.obj;
@@ -147,8 +151,7 @@
if (t == null) {
return RESULT_SUCCESS;
} else {
- if (t instanceof CommandException) {
- CommandException ce = (CommandException) t;
+ if (t instanceof CommandException ce) {
if (ce.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
return DataServiceCallback.RESULT_ERROR_UNSUPPORTED;
} else {
@@ -163,10 +166,10 @@
}
@Override
- public void setupDataCall(int accessNetworkType, DataProfile dataProfile,
+ public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties,
int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
- boolean matchAllRuleAllowed, DataServiceCallback callback) {
+ boolean matchAllRuleAllowed, @Nullable DataServiceCallback callback) {
// TODO: remove isRoaming parameter
if (DBG) log("setupDataCall " + getSlotIndex());
@@ -199,8 +202,8 @@
}
@Override
- public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
- DataServiceCallback callback) {
+ public void setInitialAttachApn(@NonNull DataProfile dataProfile, boolean isRoaming,
+ @Nullable DataServiceCallback callback) {
// TODO: remove isRoaming parameter
if (DBG) log("setInitialAttachApn " + getSlotIndex());
@@ -216,8 +219,8 @@
}
@Override
- public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
- DataServiceCallback callback) {
+ public void setDataProfile(@NonNull List<DataProfile> dps, boolean isRoaming,
+ @Nullable DataServiceCallback callback) {
// TODO: remove isRoaming parameter
if (DBG) log("setDataProfile " + getSlotIndex());
@@ -229,11 +232,11 @@
mCallbackMap.put(message, callback);
}
- mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), message);
+ mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), message);
}
@Override
- public void requestDataCallList(DataServiceCallback callback) {
+ public void requestDataCallList(@Nullable DataServiceCallback callback) {
if (DBG) log("requestDataCallList " + getSlotIndex());
Message message = null;
@@ -247,7 +250,7 @@
}
@Override
- public void startHandover(int cid, DataServiceCallback callback) {
+ public void startHandover(int cid, @Nullable DataServiceCallback callback) {
if (DBG) log("startHandover " + getSlotIndex());
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
@@ -260,7 +263,7 @@
}
@Override
- public void cancelHandover(int cid, DataServiceCallback callback) {
+ public void cancelHandover(int cid, @Nullable DataServiceCallback callback) {
Message message = null;
// Only obtain the message when the caller wants a callback. If the caller doesn't care
// the request completed or results, then no need to pass the message down.
diff --git a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
index c1d1203..ad1a8aa 100644
--- a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
+++ b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java
@@ -20,6 +20,7 @@
import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
@@ -58,9 +59,6 @@
*/
public class CellularNetworkValidator {
private static final String LOG_TAG = "NetworkValidator";
- // If true, upon validated network cache hit, we report validationDone only when
- // network becomes available. Otherwise, we report validationDone immediately.
- private static boolean sWaitForNetworkAvailableWhenCacheHit = true;
// States of validator. Only one validation can happen at once.
// IDLE: no validation going on.
@@ -69,7 +67,7 @@
private static final int STATE_VALIDATING = 1;
// VALIDATED: validation is done and successful.
// Waiting for stopValidation() to release
- // validationg NetworkRequest.
+ // validation NetworkRequest.
private static final int STATE_VALIDATED = 2;
// Singleton instance.
@@ -79,13 +77,11 @@
private int mState = STATE_IDLE;
private int mSubId;
- private long mTimeoutInMs;
private boolean mReleaseAfterValidation;
- private NetworkRequest mNetworkRequest;
private ValidationCallback mValidationCallback;
- private Context mContext;
- private ConnectivityManager mConnectivityManager;
+ private final Context mContext;
+ private final ConnectivityManager mConnectivityManager;
@VisibleForTesting
public Handler mHandler = new Handler();
@VisibleForTesting
@@ -96,18 +92,11 @@
// A cache with fixed size. It remembers 10 most recently successfully validated networks.
private static final int VALIDATED_NETWORK_CACHE_SIZE = 10;
private final PriorityQueue<ValidatedNetwork> mValidatedNetworkPQ =
- new PriorityQueue((Comparator<ValidatedNetwork>) (n1, n2) -> {
- if (n1.mValidationTimeStamp < n2.mValidationTimeStamp) {
- return -1;
- } else if (n1.mValidationTimeStamp > n2.mValidationTimeStamp) {
- return 1;
- } else {
- return 0;
- }
- });
- private final Map<String, ValidatedNetwork> mValidatedNetworkMap = new HashMap();
+ new PriorityQueue<>((Comparator<ValidatedNetwork>) Comparator.comparingLong(
+ (ValidatedNetwork n) -> n.mValidationTimeStamp));
+ private final Map<String, ValidatedNetwork> mValidatedNetworkMap = new HashMap<>();
- private final class ValidatedNetwork {
+ private static final class ValidatedNetwork {
ValidatedNetwork(String identity, long timeStamp) {
mValidationIdentity = identity;
mValidationTimeStamp = timeStamp;
@@ -165,7 +154,6 @@
private String getValidationNetworkIdentity(int subId) {
if (!SubscriptionManager.isUsableSubscriptionId(subId)) return null;
- if (SubscriptionManagerService.getInstance() == null) return null;
Phone phone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance()
.getPhoneId(subId));
if (phone == null || phone.getServiceState() == null) return null;
@@ -270,26 +258,18 @@
stopValidation();
}
- if (!sWaitForNetworkAvailableWhenCacheHit && mValidatedNetworkCache
- .isRecentlyValidated(subId)) {
- callback.onValidationDone(true, subId);
- return;
- }
-
mState = STATE_VALIDATING;
mSubId = subId;
- mTimeoutInMs = timeoutInMs;
mValidationCallback = callback;
mReleaseAfterValidation = releaseAfterValidation;
- mNetworkRequest = createNetworkRequest();
- logd("Start validating subId " + mSubId + " mTimeoutInMs " + mTimeoutInMs
+ logd("Start validating subId " + mSubId + " timeoutInMs " + timeoutInMs
+ " mReleaseAfterValidation " + mReleaseAfterValidation);
mNetworkCallback = new ConnectivityNetworkCallback(subId);
- mConnectivityManager.requestNetwork(mNetworkRequest, mNetworkCallback, mHandler);
- mHandler.postDelayed(() -> onValidationTimeout(subId), mTimeoutInMs);
+ mConnectivityManager.requestNetwork(createNetworkRequest(), mNetworkCallback, mHandler);
+ mHandler.postDelayed(() -> onValidationTimeout(subId), timeoutInMs);
}
private synchronized void onValidationTimeout(int subId) {
@@ -351,7 +331,7 @@
mState = STATE_VALIDATED;
// If validation passed and per request to NOT release after validation, delay cleanup.
if (!mReleaseAfterValidation && passed) {
- mHandler.postDelayed(()-> stopValidation(), 500);
+ mHandler.postDelayed(this::stopValidation, 500);
} else {
stopValidation();
}
@@ -379,7 +359,7 @@
* ConnectivityManager.NetworkCallback implementation
*/
@Override
- public void onAvailable(Network network) {
+ public void onAvailable(@NonNull Network network) {
logd("network onAvailable " + network);
TelephonyMetrics.getInstance().writeNetworkValidate(
TelephonyEvent.NetworkValidationState.NETWORK_VALIDATION_STATE_AVAILABLE);
@@ -393,7 +373,7 @@
}
@Override
- public void onLosing(Network network, int maxMsToLive) {
+ public void onLosing(@NonNull Network network, int maxMsToLive) {
logd("network onLosing " + network + " maxMsToLive " + maxMsToLive);
mValidatedNetworkCache.storeLastValidationResult(
ConnectivityNetworkCallback.this.mSubId, false);
@@ -401,7 +381,7 @@
}
@Override
- public void onLost(Network network) {
+ public void onLost(@NonNull Network network) {
logd("network onLost " + network);
mValidatedNetworkCache.storeLastValidationResult(
ConnectivityNetworkCallback.this.mSubId, false);
@@ -417,7 +397,7 @@
}
@Override
- public void onCapabilitiesChanged(Network network,
+ public void onCapabilitiesChanged(@NonNull Network network,
NetworkCapabilities networkCapabilities) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
logd("onValidated");
diff --git a/src/java/com/android/internal/telephony/data/DataCallback.java b/src/java/com/android/internal/telephony/data/DataCallback.java
index 1fafe8c..05d1851 100644
--- a/src/java/com/android/internal/telephony/data/DataCallback.java
+++ b/src/java/com/android/internal/telephony/data/DataCallback.java
@@ -28,7 +28,8 @@
*/
public class DataCallback {
/** The executor of the callback. */
- private final @NonNull Executor mExecutor;
+ @NonNull
+ private final Executor mExecutor;
/**
* Constructor
@@ -43,7 +44,8 @@
* @return The executor of the callback.
*/
@VisibleForTesting
- public @NonNull Executor getExecutor() {
+ @NonNull
+ public Executor getExecutor() {
return mExecutor;
}
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 6ad89ce..40039f2 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -64,6 +64,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -163,6 +164,13 @@
/** Network type NR_SA_MMWAVE. Should not be used outside of DataConfigManager. */
private static final String DATA_CONFIG_NETWORK_TYPE_NR_SA_MMWAVE = "NR_SA_MMWAVE";
+ /**
+ * The delay in milliseconds to re-evaluate existing data networks for bootstrap sim data usage
+ * limit.
+ */
+ private static final long REEVALUATE_BOOTSTRAP_SIM_DATA_USAGE_MILLIS =
+ TimeUnit.SECONDS.toMillis(60);
+
@StringDef(prefix = {"DATA_CONFIG_NETWORK_TYPE_"}, value = {
DATA_CONFIG_NETWORK_TYPE_GPRS,
DATA_CONFIG_NETWORK_TYPE_EDGE,
@@ -878,6 +886,21 @@
}
/**
+ * @return the interval in millisecond used to re-evaluate bootstrap sim data usage during esim
+ * bootstrap activation
+ */
+ public long getReevaluateBootstrapSimDataUsageMillis() {
+ long bootStrapSimDataUsageReevaluateInterval = mResources.getInteger(
+ com.android.internal.R.integer.config_reevaluate_bootstrap_sim_data_usage_millis);
+
+ if (bootStrapSimDataUsageReevaluateInterval <= 0) {
+ bootStrapSimDataUsageReevaluateInterval = REEVALUATE_BOOTSTRAP_SIM_DATA_USAGE_MILLIS;
+ }
+
+ return bootStrapSimDataUsageReevaluateInterval;
+ }
+
+ /**
* Update the TCP buffer sizes from the resource overlays.
*/
private void updateTcpBuffers() {
diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java
index a54884f..ae7023e 100644
--- a/src/java/com/android/internal/telephony/data/DataEvaluation.java
+++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java
@@ -36,18 +36,23 @@
*/
public class DataEvaluation {
/** The reason for this evaluation */
- private final @NonNull DataEvaluationReason mDataEvaluationReason;
+ @NonNull
+ private final DataEvaluationReason mDataEvaluationReason;
/** Data disallowed reasons. There could be multiple reasons for not allowing data. */
- private final @NonNull Set<DataDisallowedReason> mDataDisallowedReasons = new HashSet<>();
+ @NonNull
+ private final Set<DataDisallowedReason> mDataDisallowedReasons = new HashSet<>();
/** Data allowed reason. It is intended to only have one allowed reason. */
- private @NonNull DataAllowedReason mDataAllowedReason = DataAllowedReason.NONE;
+ @NonNull
+ private DataAllowedReason mDataAllowedReason = DataAllowedReason.NONE;
- private @Nullable DataProfile mCandidateDataProfile = null;
+ @Nullable
+ private DataProfile mCandidateDataProfile = null;
/** The timestamp of evaluation time */
- private @CurrentTimeMillisLong long mEvaluatedTime = 0;
+ @CurrentTimeMillisLong
+ private long mEvaluatedTime = 0;
/**
* Constructor
@@ -418,7 +423,7 @@
public String toString() {
StringBuilder evaluationStr = new StringBuilder();
evaluationStr.append("Data evaluation: evaluation reason:" + mDataEvaluationReason + ", ");
- if (mDataDisallowedReasons.size() > 0) {
+ if (!mDataDisallowedReasons.isEmpty()) {
evaluationStr.append("Data disallowed reasons:");
for (DataDisallowedReason reason : mDataDisallowedReasons) {
evaluationStr.append(" ").append(reason);
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index bd98403..9e84a77 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -103,6 +103,7 @@
import com.android.internal.telephony.data.TelephonyNetworkAgent.TelephonyNetworkAgentCallback;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.metrics.DataCallSessionStats;
+import com.android.internal.telephony.metrics.DataNetworkValidationStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FunctionalUtils;
@@ -200,6 +201,9 @@
/** Event for bandwidth estimation from the modem changed. */
private static final int EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED = 11;
+ /** Event to report anomaly {@link #EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE} not received. */
+ private static final int EVENT_CANCEL_HANDOVER_NO_RESPONSE = 12;
+
/** Event for display info changed. This is for getting 5G NSA or mmwave information. */
private static final int EVENT_DISPLAY_INFO_CHANGED = 13;
@@ -269,17 +273,6 @@
/** Invalid context id. */
private static final int INVALID_CID = -1;
- /**
- * The data network providing default internet will have a higher score of 50. Other network
- * will have a slightly lower score of 45. The intention is other connections will not cause
- * connectivity service to tear down default internet connection. For example, to validate
- * internet connection on non-default data SIM, we'll set up a temporary internet network on
- * that data SIM. In this case, score of 45 is assigned so connectivity service will not replace
- * the default internet network with it.
- */
- private static final int DEFAULT_INTERNET_NETWORK_SCORE = 50;
- private static final int OTHER_NETWORK_SCORE = 45;
-
@IntDef(prefix = {"TEAR_DOWN_REASON_"},
value = {
TEAR_DOWN_REASON_NONE,
@@ -552,6 +545,9 @@
/** Metrics of per data network connection. */
private final DataCallSessionStats mDataCallSessionStats;
+ /** Metrics of per data network validation. */
+ private final @NonNull DataNetworkValidationStats mDataNetworkValidationStats;
+
/**
* The unique context id assigned by the data service in {@link DataCallResponse#getId()}. One
* for {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN} and one for
@@ -708,7 +704,7 @@
private final boolean mIsSatellite;
/** The reason that why setting up this data network is allowed. */
- private @NonNull DataAllowedReason mDataAllowedReason;
+ private final @NonNull DataAllowedReason mDataAllowedReason;
/**
* PCO (Protocol Configuration Options) data received from the network. The first key is the
@@ -764,6 +760,12 @@
private @Nullable AccessNetworksManagerCallback mAccessNetworksManagerCallback;
/**
+ * PreciseDataConnectionState, the most recently notified. If it has never been notified, it is
+ * null.
+ */
+ private @Nullable PreciseDataConnectionState mPreciseDataConnectionState;
+
+ /**
* The network bandwidth.
*/
public static class NetworkBandwidth {
@@ -986,6 +988,7 @@
mDataNetworkControllerCallback);
mDataConfigManager = mDataNetworkController.getDataConfigManager();
mDataCallSessionStats = new DataCallSessionStats(mPhone);
+ mDataNetworkValidationStats = new DataNetworkValidationStats(mPhone);
mDataNetworkCallback = callback;
mDataProfile = dataProfile;
if (dataProfile.getTrafficDescriptor() != null) {
@@ -1175,7 +1178,7 @@
mCarrierPrivilegesCallback =
(Set<String> privilegedPackageNames, Set<Integer> privilegedUids) -> {
- log("onCarrierPrivilegesChanged, Uids=" + privilegedUids.toString());
+ log("onCarrierPrivilegesChanged, Uids=" + privilegedUids);
Message message = obtainMessage(EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED);
AsyncResult.forMessage(
message,
@@ -1327,11 +1330,13 @@
break;
}
case EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE:
+ removeMessages(EVENT_CANCEL_HANDOVER_NO_RESPONSE);
log("Notified handover cancelled.");
break;
case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED:
case EVENT_TEAR_DOWN_NETWORK:
case EVENT_STUCK_IN_TRANSIENT_STATE:
+ case EVENT_CANCEL_HANDOVER_NO_RESPONSE:
case EVENT_DISPLAY_INFO_CHANGED:
case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
case EVENT_CSS_INDICATOR_CHANGED:
@@ -1427,7 +1432,10 @@
setupData();
} else {
mRetryDelayMillis = DataCallResponse.RETRY_DURATION_UNDEFINED;
- mFailCause = DataFailCause.NO_RETRY_FAILURE;
+ if (!mFlags.keepEmptyRequestsNetwork()) {
+ // This will mark the data profile as no retry perm failure.
+ mFailCause = DataFailCause.NO_RETRY_FAILURE;
+ }
transitionTo(mDisconnectedState);
}
break;
@@ -1505,7 +1513,7 @@
int apnTypeBitmask = mDataProfile.getApnSetting() != null
? mDataProfile.getApnSetting().getApnTypeBitmask() : ApnSetting.TYPE_NONE;
- mDataCallSessionStats.onSetupDataCall(apnTypeBitmask);
+ mDataCallSessionStats.onSetupDataCall(apnTypeBitmask, isSatellite());
logl("setupData: accessNetwork="
+ AccessNetworkType.toString(accessNetwork) + ", " + mDataProfile
@@ -1553,12 +1561,7 @@
updateDataNetwork(response);
- // TODO: Evaluate all network requests and see if each request still can be
- // satisfied.
- // For requests that can't be satisfied anymore, we need to put them back to the
- // unsatisfied pool. If none of network requests can be satisfied, then there is no
- // need to mark network agent connected. Just silently deactivate the data network.
- if (mAttachedNetworkRequestList.isEmpty()) {
+ if (!mFlags.keepEmptyRequestsNetwork() && mAttachedNetworkRequestList.isEmpty()) {
log("Tear down the network since there is no live network request.");
// Directly call onTearDown here. Calling tearDown will cause deadlock because
// EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected
@@ -1645,9 +1648,7 @@
// If we've ever received PCO data before connected, now it's the time to process it.
mPcoData.getOrDefault(mCid.get(mTransport), Collections.emptyMap())
- .forEach((pcoId, pcoData) -> {
- onPcoDataChanged(pcoData);
- });
+ .forEach((pcoId, pcoData) -> onPcoDataChanged(pcoData));
mDataNetworkCallback.invokeFromExecutor(
() -> mDataNetworkCallback.onLinkStatusChanged(DataNetwork.this, mLinkStatus));
@@ -1721,6 +1722,12 @@
// Network validation request can be accepted if the data is in connected state
handleDataNetworkValidationRequest((Consumer<Integer>) msg.obj);
break;
+ case EVENT_CANCEL_HANDOVER_NO_RESPONSE:
+ reportAnomaly("Cancel handover no response within "
+ + TimeUnit.MILLISECONDS.toSeconds(
+ mDataConfigManager.getNetworkHandoverTimeoutMs())
+ + " seconds.", "ad320988-0601-4955-836a-e6b67289c294");
+ break;
default:
return NOT_HANDLED;
}
@@ -1736,6 +1743,7 @@
private final class HandoverState extends State {
@Override
public void enter() {
+ removeMessages(EVENT_CANCEL_HANDOVER_NO_RESPONSE);
sendMessageDelayed(EVENT_STUCK_IN_TRANSIENT_STATE,
mDataConfigManager.getNetworkHandoverTimeoutMs());
notifyPreciseDataConnectionState();
@@ -1919,6 +1927,9 @@
if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
unregisterForWwanEvents();
}
+ // Since NetworkValidation is able to request only in the Connected state,
+ // if ever connected, log for onDataNetworkDisconnected.
+ mDataNetworkValidationStats.onDataNetworkDisconnected(getDataNetworkType());
} else {
mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback
.onSetupDataFailed(DataNetwork.this,
@@ -2019,7 +2030,7 @@
log("Successfully attached network request " + networkRequest);
}
}
- if (failedList.size() > 0) {
+ if (!failedList.isEmpty()) {
mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback
.onAttachFailed(DataNetwork.this, failedList));
}
@@ -2184,8 +2195,7 @@
private static boolean areImmutableCapabilitiesChanged(
@NonNull NetworkCapabilities oldCapabilities,
@NonNull NetworkCapabilities newCapabilities) {
- if (oldCapabilities == null
- || ArrayUtils.isEmpty(oldCapabilities.getCapabilities())) return false;
+ if (ArrayUtils.isEmpty(oldCapabilities.getCapabilities())) return false;
// Remove mutable capabilities from both old and new capabilities, the remaining
// capabilities would be immutable capabilities.
@@ -2215,6 +2225,7 @@
// will always be registered with NOT_SUSPENDED capability.
mNetworkAgent = createNetworkAgent();
mNetworkAgent.markConnected();
+ notifyPreciseDataConnectionState();
// Because network agent is always created with NOT_SUSPENDED, we need to update
// the suspended if it's was in suspended state.
if (mSuspended) {
@@ -2443,8 +2454,8 @@
// If we find another data data profile that can support MMS on IWLAN, then remove
// the MMS capability from this cellular network. This will allow IWLAN to be
// brought up for MMS later.
- if (dataProfile != null && !dataProfile.equals(mDataProfile)) {
- log("Found a different data profile " + mDataProfile.getApn()
+ if (dataProfile != null && !dataProfile.getApn().equals(mDataProfile.getApn())) {
+ log("Found a different apn name " + mDataProfile.getApn()
+ " that can serve MMS on IWLAN.");
builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
}
@@ -2546,7 +2557,6 @@
// Never set suspended for emergency apn. Emergency data connection
// can work while device is not in service.
if (mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
- newSuspendedState = false;
// If we are not in service, change to suspended.
} else if (nri.getRegistrationState()
!= NetworkRegistrationInfo.REGISTRATION_STATE_HOME
@@ -2648,7 +2658,7 @@
}
// Set link addresses
- if (response.getAddresses().size() > 0) {
+ if (!response.getAddresses().isEmpty()) {
for (LinkAddress la : response.getAddresses()) {
if (!la.getAddress().isAnyLocalAddress()) {
logv("addr/pl=" + la.getAddress() + "/" + la.getPrefixLength());
@@ -2660,7 +2670,7 @@
}
// Set DNS servers
- if (response.getDnsAddresses().size() > 0) {
+ if (!response.getDnsAddresses().isEmpty()) {
for (InetAddress dns : response.getDnsAddresses()) {
if (!dns.isAnyLocalAddress()) {
linkProperties.addDnsServer(dns);
@@ -2671,7 +2681,7 @@
}
// Set PCSCF
- if (response.getPcscfAddresses().size() > 0) {
+ if (!response.getPcscfAddresses().isEmpty()) {
for (InetAddress pcscf : response.getPcscfAddresses()) {
linkProperties.addPcscfServer(pcscf);
}
@@ -2810,22 +2820,22 @@
== AccessNetworkConstants.TRANSPORT_TYPE_WWAN
? "RIL" : "IWLAN data service";
if (protocol == ApnSetting.PROTOCOL_IP) {
- if (response.getAddresses().stream().anyMatch(
- la -> la.getAddress() instanceof java.net.Inet6Address)) {
- loge("Invalid DataCallResponse. Requested IPv4 but got IPv6 address."
- + response);
+ if (response.getAddresses().stream().noneMatch(
+ la -> la.getAddress() instanceof java.net.Inet4Address)) {
+ loge("Invalid DataCallResponse. Requested IPv4 but didn't get an "
+ + "IPv4 address." + response);
reportAnomaly(underlyingDataService + " reported mismatched IP "
- + "type. Requested IPv4 but got IPv6 address.",
- "7744f920-fb64-4db0-ba47-de0eae485a81");
+ + "type. Requested IPv4 but didn't get an IPv4 "
+ + "address.", "7744f920-fb64-4db0-ba47-de0eae485a82");
}
} else if (protocol == ApnSetting.PROTOCOL_IPV6) {
- if (response.getAddresses().stream().anyMatch(
- la -> la.getAddress() instanceof java.net.Inet4Address)) {
- loge("Invalid DataCallResponse. Requested IPv6 but got IPv4 address."
- + response);
+ if (response.getAddresses().stream().noneMatch(
+ la -> la.getAddress() instanceof java.net.Inet6Address)) {
+ loge("Invalid DataCallResponse. Requested IPv6 but didn't get an "
+ + "IPv6 address." + response);
reportAnomaly(underlyingDataService + " reported mismatched IP "
- + "type. Requested IPv6 but got IPv4 address.",
- "7744f920-fb64-4db0-ba47-de0eae485a81");
+ + "type. Requested IPv6 but didn't get an IPv6 "
+ + "address.", "7744f920-fb64-4db0-ba47-de0eae485a82");
}
}
}
@@ -2967,6 +2977,7 @@
mDataCallResponse = response;
if (response.getLinkStatus() != DataCallResponse.LINK_STATUS_INACTIVE) {
updateDataNetwork(response);
+ notifyPreciseDataConnectionState();
} else {
log("onDataStateChanged: PDN inactive reported by "
+ AccessNetworkConstants.transportTypeToString(mTransport)
@@ -3040,12 +3051,12 @@
NetworkBandwidth bandwidthFromConfig = mDataConfigManager.getBandwidthForNetworkType(
mTelephonyDisplayInfo);
- if (downlinkBandwidthKbps == LinkCapacityEstimate.INVALID && bandwidthFromConfig != null) {
+ if (downlinkBandwidthKbps == LinkCapacityEstimate.INVALID) {
// Fallback to carrier config.
downlinkBandwidthKbps = bandwidthFromConfig.downlinkBandwidthKbps;
}
- if (uplinkBandwidthKbps == LinkCapacityEstimate.INVALID && bandwidthFromConfig != null) {
+ if (uplinkBandwidthKbps == LinkCapacityEstimate.INVALID) {
// Fallback to carrier config.
uplinkBandwidthKbps = bandwidthFromConfig.uplinkBandwidthKbps;
}
@@ -3404,6 +3415,7 @@
return new PreciseDataConnectionState.Builder()
.setTransportType(mTransport)
.setId(mCid.get(mTransport))
+ .setNetworkAgentId(mNetworkAgent.getId())
.setState(getState())
.setApnSetting(mDataProfile.getApnSetting())
.setLinkProperties(mLinkProperties)
@@ -3417,11 +3429,22 @@
/**
* Send the precise data connection state to the listener of
* {@link android.telephony.TelephonyCallback.PreciseDataConnectionStateListener}.
+ *
+ * Note that notify only when {@link DataState} or {@link
+ * PreciseDataConnectionState.NetworkValidationStatus} or {@link TelephonyNetworkAgent#getId}
+ * changes.
*/
private void notifyPreciseDataConnectionState() {
PreciseDataConnectionState pdcs = getPreciseDataConnectionState();
- logv("notifyPreciseDataConnectionState=" + pdcs);
- mPhone.notifyDataConnection(pdcs);
+ if (mPreciseDataConnectionState == null
+ || mPreciseDataConnectionState.getState() != pdcs.getState()
+ || mPreciseDataConnectionState.getNetworkValidationStatus()
+ != pdcs.getNetworkValidationStatus()
+ || mPreciseDataConnectionState.getNetId() != pdcs.getNetId()) {
+ mPreciseDataConnectionState = pdcs;
+ logv("notifyPreciseDataConnectionState=" + pdcs);
+ mPhone.notifyDataConnection(pdcs);
+ }
}
/**
@@ -3511,6 +3534,8 @@
DataService.REQUEST_REASON_HANDOVER, mLinkProperties, mPduSessionId,
mNetworkSliceInfo, mHandoverDataProfile.getTrafficDescriptor(), true,
obtainMessage(EVENT_HANDOVER_RESPONSE, retryEntry));
+
+ mDataNetworkValidationStats.onHandoverAttempted();
}
/**
@@ -3558,6 +3583,8 @@
// id can be released if it is preserved for handover.
mDataServiceManagers.get(mTransport).cancelHandover(mCid.get(mTransport),
obtainMessage(EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE));
+ sendMessageDelayed(EVENT_CANCEL_HANDOVER_NO_RESPONSE,
+ mDataConfigManager.getNetworkHandoverTimeoutMs());
long retry = response != null ? response.getRetryDurationMillis()
: DataCallResponse.RETRY_DURATION_UNDEFINED;
@@ -3681,7 +3708,7 @@
}
/**
- * The network validation requests moves to process on the statemachich handler. A request is
+ * The network validation requests moves to process on the state machine handler. A request is
* processed according to state of the data network.
*/
public void requestNetworkValidation(@NonNull Consumer<Integer> resultCodeCallback) {
@@ -3705,6 +3732,11 @@
// Request validation directly from the data service.
mDataServiceManagers.get(mTransport).requestNetworkValidation(
mCid.get(mTransport), obtainMessage(EVENT_DATA_NETWORK_VALIDATION_RESPONSE));
+
+ int apnTypeBitmask = mDataProfile.getApnSetting() != null
+ ? mDataProfile.getApnSetting().getApnTypeBitmask() : ApnSetting.TYPE_NONE;
+ mDataNetworkValidationStats.onRequestNetworkValidation(apnTypeBitmask);
+
log("handleDataNetworkValidationRequest, network validation requested");
}
@@ -3733,8 +3765,7 @@
/**
* Update the validation status from {@link DataCallResponse}, convert to network validation
- * status {@link PreciseDataConnectionState.NetworkValidationStatus} and notify to
- * {@link PreciseDataConnectionState} if status was changed.
+ * status {@link PreciseDataConnectionState.NetworkValidationStatus}.
*
* @param networkValidationStatus {@link PreciseDataConnectionState.NetworkValidationStatus}
*/
@@ -3751,8 +3782,10 @@
+ PreciseDataConnectionState.networkValidationStatusToString(
networkValidationStatus));
mNetworkValidationStatus = networkValidationStatus;
- notifyPreciseDataConnectionState();
}
+
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ mNetworkValidationStatus, getDataNetworkType());
}
/**
@@ -3762,76 +3795,52 @@
* @return The deactivation reason in string format.
*/
public static @NonNull String tearDownReasonToString(@TearDownReason int reason) {
- switch (reason) {
- case TEAR_DOWN_REASON_NONE:
- return "NONE";
- case TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED:
- return "CONNECTIVITY_SERVICE_UNWANTED";
- case TEAR_DOWN_REASON_SIM_REMOVAL:
- return "SIM_REMOVAL";
- case TEAR_DOWN_REASON_AIRPLANE_MODE_ON:
- return "AIRPLANE_MODE_ON";
- case TEAR_DOWN_REASON_DATA_DISABLED:
- return "DATA_DISABLED";
- case TEAR_DOWN_REASON_NO_LIVE_REQUEST:
- return "TEAR_DOWN_REASON_NO_LIVE_REQUEST";
- case TEAR_DOWN_REASON_RAT_NOT_ALLOWED:
- return "TEAR_DOWN_REASON_RAT_NOT_ALLOWED";
- case TEAR_DOWN_REASON_ROAMING_DISABLED:
- return "TEAR_DOWN_REASON_ROAMING_DISABLED";
- case TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED:
- return "TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED";
- case TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED:
- return "TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED";
- case TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY:
- return "TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY";
- case TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER:
- return "TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER";
- case TEAR_DOWN_REASON_DATA_STALL:
- return "TEAR_DOWN_REASON_DATA_STALL";
- case TEAR_DOWN_REASON_HANDOVER_FAILED:
- return "TEAR_DOWN_REASON_HANDOVER_FAILED";
- case TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED:
- return "TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED";
- case TEAR_DOWN_REASON_VCN_REQUESTED:
- return "TEAR_DOWN_REASON_VCN_REQUESTED";
- case TEAR_DOWN_REASON_VOPS_NOT_SUPPORTED:
- return "TEAR_DOWN_REASON_VOPS_NOT_SUPPORTED";
- case TEAR_DOWN_REASON_DEFAULT_DATA_UNSELECTED:
- return "TEAR_DOWN_REASON_DEFAULT_DATA_UNSELECTED";
- case TEAR_DOWN_REASON_NOT_IN_SERVICE:
- return "TEAR_DOWN_REASON_NOT_IN_SERVICE";
- case TEAR_DOWN_REASON_DATA_CONFIG_NOT_READY:
- return "TEAR_DOWN_REASON_DATA_CONFIG_NOT_READY";
- case TEAR_DOWN_REASON_PENDING_TEAR_DOWN_ALL:
- return "TEAR_DOWN_REASON_PENDING_TEAR_DOWN_ALL";
- case TEAR_DOWN_REASON_NO_SUITABLE_DATA_PROFILE:
- return "TEAR_DOWN_REASON_NO_SUITABLE_DATA_PROFILE";
- case TEAR_DOWN_REASON_CDMA_EMERGENCY_CALLBACK_MODE:
- return "TEAR_DOWN_REASON_CDMA_EMERGENCY_CALLBACK_MODE";
- case TEAR_DOWN_REASON_RETRY_SCHEDULED:
- return "TEAR_DOWN_REASON_RETRY_SCHEDULED";
- case TEAR_DOWN_REASON_DATA_THROTTLED:
- return "TEAR_DOWN_REASON_DATA_THROTTLED";
- case TEAR_DOWN_REASON_DATA_PROFILE_INVALID:
- return "TEAR_DOWN_REASON_DATA_PROFILE_INVALID";
- case TEAR_DOWN_REASON_DATA_PROFILE_NOT_PREFERRED:
- return "TEAR_DOWN_REASON_DATA_PROFILE_NOT_PREFERRED";
- case TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY:
- return "TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY";
- case TEAR_DOWN_REASON_ILLEGAL_STATE:
- return "TEAR_DOWN_REASON_ILLEGAL_STATE";
- case TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK:
- return "TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK";
- case TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED:
- return "TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED";
- case TEAR_DOWN_REASON_DATA_LIMIT_REACHED:
- return "TEAR_DOWN_REASON_DATA_LIMIT_REACHED";
- case TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED:
- return "TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED";
- default:
- return "UNKNOWN(" + reason + ")";
- }
+ return switch (reason) {
+ case TEAR_DOWN_REASON_NONE -> "NONE";
+ case TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED -> "CONNECTIVITY_SERVICE_UNWANTED";
+ case TEAR_DOWN_REASON_SIM_REMOVAL -> "SIM_REMOVAL";
+ case TEAR_DOWN_REASON_AIRPLANE_MODE_ON -> "AIRPLANE_MODE_ON";
+ case TEAR_DOWN_REASON_DATA_DISABLED -> "DATA_DISABLED";
+ case TEAR_DOWN_REASON_NO_LIVE_REQUEST -> "TEAR_DOWN_REASON_NO_LIVE_REQUEST";
+ case TEAR_DOWN_REASON_RAT_NOT_ALLOWED -> "TEAR_DOWN_REASON_RAT_NOT_ALLOWED";
+ case TEAR_DOWN_REASON_ROAMING_DISABLED -> "TEAR_DOWN_REASON_ROAMING_DISABLED";
+ case TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED ->
+ "TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED";
+ case TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED ->
+ "TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED";
+ case TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY ->
+ "TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY";
+ case TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER -> "TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER";
+ case TEAR_DOWN_REASON_DATA_STALL -> "TEAR_DOWN_REASON_DATA_STALL";
+ case TEAR_DOWN_REASON_HANDOVER_FAILED -> "TEAR_DOWN_REASON_HANDOVER_FAILED";
+ case TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED -> "TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED";
+ case TEAR_DOWN_REASON_VCN_REQUESTED -> "TEAR_DOWN_REASON_VCN_REQUESTED";
+ case TEAR_DOWN_REASON_VOPS_NOT_SUPPORTED -> "TEAR_DOWN_REASON_VOPS_NOT_SUPPORTED";
+ case TEAR_DOWN_REASON_DEFAULT_DATA_UNSELECTED ->
+ "TEAR_DOWN_REASON_DEFAULT_DATA_UNSELECTED";
+ case TEAR_DOWN_REASON_NOT_IN_SERVICE -> "TEAR_DOWN_REASON_NOT_IN_SERVICE";
+ case TEAR_DOWN_REASON_DATA_CONFIG_NOT_READY -> "TEAR_DOWN_REASON_DATA_CONFIG_NOT_READY";
+ case TEAR_DOWN_REASON_PENDING_TEAR_DOWN_ALL -> "TEAR_DOWN_REASON_PENDING_TEAR_DOWN_ALL";
+ case TEAR_DOWN_REASON_NO_SUITABLE_DATA_PROFILE ->
+ "TEAR_DOWN_REASON_NO_SUITABLE_DATA_PROFILE";
+ case TEAR_DOWN_REASON_CDMA_EMERGENCY_CALLBACK_MODE ->
+ "TEAR_DOWN_REASON_CDMA_EMERGENCY_CALLBACK_MODE";
+ case TEAR_DOWN_REASON_RETRY_SCHEDULED -> "TEAR_DOWN_REASON_RETRY_SCHEDULED";
+ case TEAR_DOWN_REASON_DATA_THROTTLED -> "TEAR_DOWN_REASON_DATA_THROTTLED";
+ case TEAR_DOWN_REASON_DATA_PROFILE_INVALID -> "TEAR_DOWN_REASON_DATA_PROFILE_INVALID";
+ case TEAR_DOWN_REASON_DATA_PROFILE_NOT_PREFERRED ->
+ "TEAR_DOWN_REASON_DATA_PROFILE_NOT_PREFERRED";
+ case TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY -> "TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY";
+ case TEAR_DOWN_REASON_ILLEGAL_STATE -> "TEAR_DOWN_REASON_ILLEGAL_STATE";
+ case TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK ->
+ "TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK";
+ case TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED ->
+ "TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED";
+ case TEAR_DOWN_REASON_DATA_LIMIT_REACHED -> "TEAR_DOWN_REASON_DATA_LIMIT_REACHED";
+ case TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED ->
+ "TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED";
+ default -> "UNKNOWN(" + reason + ")";
+ };
}
/**
@@ -3841,64 +3850,41 @@
* @return The event in string format.
*/
private static @NonNull String eventToString(int event) {
- switch (event) {
- case EVENT_DATA_CONFIG_UPDATED:
- return "EVENT_DATA_CONFIG_UPDATED";
- case EVENT_ATTACH_NETWORK_REQUEST:
- return "EVENT_ATTACH_NETWORK_REQUEST";
- case EVENT_DETACH_NETWORK_REQUEST:
- return "EVENT_DETACH_NETWORK_REQUEST";
- case EVENT_RADIO_NOT_AVAILABLE:
- return "EVENT_RADIO_NOT_AVAILABLE";
- case EVENT_ALLOCATE_PDU_SESSION_ID_RESPONSE:
- return "EVENT_ALLOCATE_PDU_SESSION_ID_RESPONSE";
- case EVENT_SETUP_DATA_NETWORK_RESPONSE:
- return "EVENT_SETUP_DATA_NETWORK_RESPONSE";
- case EVENT_TEAR_DOWN_NETWORK:
- return "EVENT_TEAR_DOWN_NETWORK";
- case EVENT_DATA_STATE_CHANGED:
- return "EVENT_DATA_STATE_CHANGED";
- case EVENT_SERVICE_STATE_CHANGED:
- return "EVENT_DATA_NETWORK_TYPE_REG_STATE_CHANGED";
- case EVENT_DETACH_ALL_NETWORK_REQUESTS:
- return "EVENT_DETACH_ALL_NETWORK_REQUESTS";
- case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED:
- return "EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED";
- case EVENT_DISPLAY_INFO_CHANGED:
- return "EVENT_DISPLAY_INFO_CHANGED";
- case EVENT_HANDOVER_RESPONSE:
- return "EVENT_HANDOVER_RESPONSE";
- case EVENT_SUBSCRIPTION_PLAN_OVERRIDE:
- return "EVENT_SUBSCRIPTION_PLAN_OVERRIDE";
- case EVENT_PCO_DATA_RECEIVED:
- return "EVENT_PCO_DATA_RECEIVED";
- case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED:
- return "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED";
- case EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE:
- return "EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE";
- case EVENT_STUCK_IN_TRANSIENT_STATE:
- return "EVENT_STUCK_IN_TRANSIENT_STATE";
- case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET:
- return "EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET";
- case EVENT_VOICE_CALL_STARTED:
- return "EVENT_VOICE_CALL_STARTED";
- case EVENT_VOICE_CALL_ENDED:
- return "EVENT_VOICE_CALL_ENDED";
- case EVENT_CSS_INDICATOR_CHANGED:
- return "EVENT_CSS_INDICATOR_CHANGED";
- case EVENT_NOTIFY_HANDOVER_STARTED:
- return "EVENT_NOTIFY_HANDOVER_STARTED";
- case EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE:
- return "EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE";
- case EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE:
- return "EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE";
- case EVENT_DATA_NETWORK_VALIDATION_REQUESTED:
- return "EVENT_DATA_NETWORK_VALIDATION_REQUESTED";
- case EVENT_DATA_NETWORK_VALIDATION_RESPONSE:
- return "EVENT_DATA_NETWORK_VALIDATION_RESPONSE";
- default:
- return "Unknown(" + event + ")";
- }
+ return switch (event) {
+ case EVENT_DATA_CONFIG_UPDATED -> "EVENT_DATA_CONFIG_UPDATED";
+ case EVENT_ATTACH_NETWORK_REQUEST -> "EVENT_ATTACH_NETWORK_REQUEST";
+ case EVENT_DETACH_NETWORK_REQUEST -> "EVENT_DETACH_NETWORK_REQUEST";
+ case EVENT_RADIO_NOT_AVAILABLE -> "EVENT_RADIO_NOT_AVAILABLE";
+ case EVENT_ALLOCATE_PDU_SESSION_ID_RESPONSE -> "EVENT_ALLOCATE_PDU_SESSION_ID_RESPONSE";
+ case EVENT_SETUP_DATA_NETWORK_RESPONSE -> "EVENT_SETUP_DATA_NETWORK_RESPONSE";
+ case EVENT_TEAR_DOWN_NETWORK -> "EVENT_TEAR_DOWN_NETWORK";
+ case EVENT_DATA_STATE_CHANGED -> "EVENT_DATA_STATE_CHANGED";
+ case EVENT_SERVICE_STATE_CHANGED -> "EVENT_DATA_NETWORK_TYPE_REG_STATE_CHANGED";
+ case EVENT_DETACH_ALL_NETWORK_REQUESTS -> "EVENT_DETACH_ALL_NETWORK_REQUESTS";
+ case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED ->
+ "EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED";
+ case EVENT_CANCEL_HANDOVER_NO_RESPONSE -> "EVENT_CANCEL_HANDOVER_NO_RESPONSE";
+ case EVENT_DISPLAY_INFO_CHANGED -> "EVENT_DISPLAY_INFO_CHANGED";
+ case EVENT_HANDOVER_RESPONSE -> "EVENT_HANDOVER_RESPONSE";
+ case EVENT_SUBSCRIPTION_PLAN_OVERRIDE -> "EVENT_SUBSCRIPTION_PLAN_OVERRIDE";
+ case EVENT_PCO_DATA_RECEIVED -> "EVENT_PCO_DATA_RECEIVED";
+ case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED -> "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED";
+ case EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE -> "EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE";
+ case EVENT_STUCK_IN_TRANSIENT_STATE -> "EVENT_STUCK_IN_TRANSIENT_STATE";
+ case EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET ->
+ "EVENT_WAITING_FOR_TEARING_DOWN_CONDITION_MET";
+ case EVENT_VOICE_CALL_STARTED -> "EVENT_VOICE_CALL_STARTED";
+ case EVENT_VOICE_CALL_ENDED -> "EVENT_VOICE_CALL_ENDED";
+ case EVENT_CSS_INDICATOR_CHANGED -> "EVENT_CSS_INDICATOR_CHANGED";
+ case EVENT_NOTIFY_HANDOVER_STARTED -> "EVENT_NOTIFY_HANDOVER_STARTED";
+ case EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE -> "EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE";
+ case EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE ->
+ "EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE";
+ case EVENT_DATA_NETWORK_VALIDATION_REQUESTED ->
+ "EVENT_DATA_NETWORK_VALIDATION_REQUESTED";
+ case EVENT_DATA_NETWORK_VALIDATION_RESPONSE -> "EVENT_DATA_NETWORK_VALIDATION_RESPONSE";
+ default -> "Unknown(" + event + ")";
+ };
}
@Override
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 2725295..3104d9e 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.data;
import android.annotation.CallbackExecutor;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +39,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
@@ -244,17 +246,22 @@
TimeUnit.SECONDS.toMillis(1);
/**
- * The delay in milliseconds to re-evaluate existing data networks for bootstrap sim data usage
- * limit.
+ * The guard timer in milliseconds to limit querying the data usage api stats frequently
*/
- private static final long REEVALUATE_BOOTSTRAP_SIM_DATA_USAGE_MILLIS =
- TimeUnit.SECONDS.toMillis(60);
+ private static final long GUARD_TIMER_INTERVAL_TO_QUERY_DATA_USAGE_API_STATS_MILLIS =
+ TimeUnit.SECONDS.toMillis(1);
/**
* bootstrap sim total data usage bytes
*/
private long mBootStrapSimTotalDataUsageBytes = 0L;
+ /**
+ * bootstrap sim last data usage query time
+ */
+ @ElapsedRealtimeLong
+ private long mBootstrapSimLastDataUsageQueryTime = 0L;
+
private final Phone mPhone;
private final String mLogTag;
private final LocalLog mLocalLog = new LocalLog(128);
@@ -393,12 +400,6 @@
private @NonNull SlidingWindowEventCounter mSetupDataCallWwanFailureCounter;
/**
- * {@code true} if {@link #tearDownAllDataNetworks(int)} was invoked and waiting for all
- * networks torn down.
- */
- private boolean mPendingTearDownAllNetworks = false;
-
- /**
* The capabilities of the latest released IMS request. To detect back to back release/request
* IMS network.
*/
@@ -1621,7 +1622,7 @@
}
// Check if there are pending tear down all networks request.
- if (mPendingTearDownAllNetworks) {
+ if (mPhone.getServiceStateTracker().isPendingRadioPowerOffAfterDataOff()) {
evaluation.addDataDisallowedReason(DataDisallowedReason.PENDING_TEAR_DOWN_ALL);
}
@@ -1760,7 +1761,8 @@
* - At evaluation network request and evaluation data network determines, if
* bootstrap sim current data usage reached bootstrap sim max data limit allowed set
* at {@link DataConfigManager#getEsimBootStrapMaxDataLimitBytes()}
- * - Query the current data usage at {@link #getDataUsage()}
+ * - Query the current data usage at {@link #getDataUsage()}, if last data usage query guarding
+ * interval as expired.
*
* @return true, if bootstrap sim data limit is reached
* else false, if bootstrap sim max data limit allowed set is -1(Unlimited) or current
@@ -1775,13 +1777,15 @@
return false;
}
- log("current bootstrap sim data Usage: " + mBootStrapSimTotalDataUsageBytes);
- if (mBootStrapSimTotalDataUsageBytes >= esimBootStrapMaxDataLimitBytes) {
- return true;
- } else {
+ if (mBootStrapSimTotalDataUsageBytes < esimBootStrapMaxDataLimitBytes
+ && (mBootstrapSimLastDataUsageQueryTime == 0
+ || SystemClock.elapsedRealtime() - mBootstrapSimLastDataUsageQueryTime
+ > GUARD_TIMER_INTERVAL_TO_QUERY_DATA_USAGE_API_STATS_MILLIS)) {
mBootStrapSimTotalDataUsageBytes = getDataUsage();
- return mBootStrapSimTotalDataUsageBytes >= esimBootStrapMaxDataLimitBytes;
+ log("current bootstrap sim data usage: " + mBootStrapSimTotalDataUsageBytes);
+ mBootstrapSimLastDataUsageQueryTime = SystemClock.elapsedRealtime();
}
+ return mBootStrapSimTotalDataUsageBytes >= esimBootStrapMaxDataLimitBytes;
}
/**
@@ -1801,8 +1805,7 @@
if (!TextUtils.isEmpty(subscriberId)) {
builder.setSubscriberIds(Set.of(subscriberId));
- // Consider data usage calculation of only metered network.
- // Emergency data usage is excluded.
+ // Consider data usage calculation of only metered capabilities / data network
builder.setMeteredness(android.net.NetworkStats.METERED_YES);
NetworkTemplate template = builder.build();
final NetworkStats.Bucket ret = networkStatsManager
@@ -1926,7 +1929,7 @@
if (!hasMessages(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)) {
sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS,
DataEvaluationReason.CHECK_DATA_USAGE),
- REEVALUATE_BOOTSTRAP_SIM_DATA_USAGE_MILLIS);
+ mDataConfigManager.getReevaluateBootstrapSimDataUsageMillis());
} else {
log("skip scheduling evaluating existing data networks since already"
+ "scheduled");
@@ -2935,7 +2938,6 @@
mDataNetworkList.remove(dataNetwork);
trackSetupDataCallFailure(dataNetwork.getTransport(), cause);
if (mAnyDataNetworkExisting && mDataNetworkList.isEmpty()) {
- mPendingTearDownAllNetworks = false;
mAnyDataNetworkExisting = false;
mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
() -> callback.onAnyDataNetworkExistingChanged(mAnyDataNetworkExisting)));
@@ -3036,7 +3038,7 @@
if (isEsimBootStrapProvisioningActivated()) {
sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS,
DataEvaluationReason.CHECK_DATA_USAGE),
- REEVALUATE_BOOTSTRAP_SIM_DATA_USAGE_MILLIS);
+ mDataConfigManager.getReevaluateBootstrapSimDataUsageMillis());
}
}
@@ -3203,7 +3205,13 @@
return;
}
- if (dataNetwork.isInternetSupported()) {
+ // Only track the networks that require validation.
+ // The criteria is base on NetworkMonitorUtils.java.
+ NetworkCapabilities capabilities = dataNetwork.getNetworkCapabilities();
+ if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)) {
if (status == NetworkAgent.VALIDATION_STATUS_NOT_VALID
&& (dataNetwork.getCurrentState() == null || dataNetwork.isDisconnected())) {
log("Ignoring invalid validation status for disconnected DataNetwork");
@@ -3260,7 +3268,6 @@
if (mAnyDataNetworkExisting && mDataNetworkList.isEmpty()) {
log("All data networks disconnected now.");
- mPendingTearDownAllNetworks = false;
mAnyDataNetworkExisting = false;
mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor(
() -> callback.onAnyDataNetworkExistingChanged(mAnyDataNetworkExisting)));
@@ -3994,14 +4001,13 @@
*
* @param reason The reason to tear down.
*/
- public void onTearDownAllDataNetworks(@TearDownReason int reason) {
+ private void onTearDownAllDataNetworks(@TearDownReason int reason) {
log("onTearDownAllDataNetworks: reason=" + DataNetwork.tearDownReasonToString(reason));
if (mDataNetworkList.isEmpty()) {
log("tearDownAllDataNetworks: No pending networks. All disconnected now.");
return;
}
- mPendingTearDownAllNetworks = true;
for (DataNetwork dataNetwork : mDataNetworkList) {
if (!dataNetwork.isDisconnecting()) {
tearDownGracefully(dataNetwork, reason);
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index 0da220b..2a2a792 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -45,6 +45,7 @@
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
+import android.util.LruCache;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
@@ -102,8 +103,9 @@
/** The preferred data profile used for internet. */
private @Nullable DataProfile mPreferredDataProfile = null;
- /** The last data profile that's successful for internet connection. */
- private @Nullable DataProfile mLastInternetDataProfile = null;
+ /** The last data profile that's successful for internet connection by subscription id. */
+ private final @NonNull LruCache<Integer, DataProfile> mLastInternetDataProfiles =
+ new LruCache<>(256);
/** Preferred data profile set id. */
private int mPreferredDataProfileSetId = Telephony.Carriers.NO_APN_SET_ID;
@@ -452,9 +454,11 @@
}
}
- // Update a working internet data profile as a future candidate for preferred data profile
- // after APNs are reset to default
- mLastInternetDataProfile = defaultProfile;
+ // Update a working internet data profile by subid as a future candidate for preferred
+ // data profile after APNs are reset to default
+ if (defaultProfile != null) {
+ mLastInternetDataProfiles.put(mPhone.getSubId(), defaultProfile);
+ }
// If the live default internet network is not using the preferred data profile, since
// brought up a network means it passed sophisticated checks, update the preferred data
@@ -542,7 +546,8 @@
*/
private boolean updatePreferredDataProfile() {
DataProfile preferredDataProfile;
- if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+ int subId = mPhone.getSubId();
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
preferredDataProfile = getPreferredDataProfileFromDb();
if (preferredDataProfile == null) {
preferredDataProfile = getPreferredDataProfileFromConfig();
@@ -551,7 +556,8 @@
setPreferredDataProfile(preferredDataProfile);
} else {
preferredDataProfile = mAllDataProfiles.stream()
- .filter(dp -> areDataProfilesSharingApn(dp, mLastInternetDataProfile))
+ .filter(dp -> areDataProfilesSharingApn(dp,
+ mLastInternetDataProfiles.get(subId)))
.findFirst()
.orElse(null);
if (preferredDataProfile != null) {
@@ -597,7 +603,7 @@
// Sort the data profiles so the preferred data profile is at the beginning.
List<DataProfile> allDataProfiles = mAllDataProfiles.stream()
.sorted(Comparator.comparing((DataProfile dp) -> !dp.equals(mPreferredDataProfile)))
- .collect(Collectors.toList());
+ .toList();
// Search in the order. "IA" type should be the first from getAllowedInitialAttachApnTypes.
for (int apnType : mDataConfigManager.getAllowedInitialAttachApnTypes()) {
initialAttachDataProfile = allDataProfiles.stream()
@@ -793,7 +799,7 @@
logv("Satisfied profile: " + dataProfile + ", last setup="
+ DataUtils.elapsedTimeToString(dataProfile.getLastSetupTimestamp()));
}
- if (dataProfiles.size() == 0) {
+ if (dataProfiles.isEmpty()) {
log("Can't find any data profile that can satisfy " + networkRequest);
return null;
}
@@ -810,16 +816,14 @@
ApnSetting.INFRASTRUCTURE_SATELLITE)) {
return false;
}
- if (!isNtn && !dp.getApnSetting().isForInfrastructure(
- ApnSetting.INFRASTRUCTURE_CELLULAR)) {
- return false;
- }
+ return isNtn || dp.getApnSetting().isForInfrastructure(
+ ApnSetting.INFRASTRUCTURE_CELLULAR);
}
return true;
})
.collect(Collectors.toList());
- if (dataProfiles.size() == 0) {
+ if (dataProfiles.isEmpty()) {
String ntnReason = "";
if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
ntnReason = " and infrastructure for "
@@ -837,7 +841,7 @@
== Telephony.Carriers.MATCH_ALL_APN_SET_ID
|| dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
.collect(Collectors.toList());
- if (dataProfiles.size() == 0) {
+ if (dataProfiles.isEmpty()) {
log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId="
+ mPreferredDataProfileSetId);
return null;
@@ -845,9 +849,10 @@
// Check if data profiles are permanently failed.
dataProfiles = dataProfiles.stream()
- .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed())
+ .filter(dp -> ignorePermanentFailure || (dp.getApnSetting() != null
+ && !dp.getApnSetting().getPermanentFailed()))
.collect(Collectors.toList());
- if (dataProfiles.size() == 0) {
+ if (dataProfiles.isEmpty()) {
log("The suitable data profiles are all in permanent failed state.");
return null;
}
@@ -939,7 +944,8 @@
* @param setting The Apn setting to be checked.
*/
private void checkApnSetting(@NonNull ApnSetting setting) {
- if (setting.canHandleType(ApnSetting.TYPE_MMS)) {
+ if (setting.canHandleType(ApnSetting.TYPE_MMS)
+ && setting.getEditedStatus() == Telephony.Carriers.UNEDITED) {
if (setting.getMmsc() == null) {
reportAnomaly("MMS is supported but no MMSC configured " + setting,
"9af73e18-b523-4dc5-adab-19d86c6a3685");
@@ -965,7 +971,7 @@
private void checkDataProfiles(List<DataProfile> profiles) {
for (int i = 0; i < profiles.size(); i++) {
ApnSetting a = profiles.get(i).getApnSetting();
- if (a == null) continue;
+ if (a == null || a.getEditedStatus() != Telephony.Carriers.UNEDITED) continue;
if (// Lingering network is not the default and doesn't cover all the regular networks
(int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN
!= a.getLingeringNetworkTypeBitmask()
@@ -979,23 +985,6 @@
a.getLingeringNetworkTypeBitmask()),
"9af73e18-b523-4dc5-adab-4bb24355d838");
}
- for (int j = i + 1; j < profiles.size(); j++) {
- ApnSetting b = profiles.get(j).getApnSetting();
- if (b == null) continue;
- String apnNameA = a.getApnName();
- String apnNameB = b.getApnName();
- if (TextUtils.equals(apnNameA, apnNameB)
- // TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN means all network types
- && (a.getNetworkTypeBitmask()
- == (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN
- || b.getNetworkTypeBitmask()
- == (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN
- || (a.getNetworkTypeBitmask() & b.getNetworkTypeBitmask()) != 0)) {
- reportAnomaly("Found overlapped network type under the APN name "
- + a.getApnName(),
- "9af73e18-b523-4dc5-adab-4bb24555d839");
- }
- }
}
}
@@ -1106,10 +1095,6 @@
* @return {@code true} if the provided data profile can be still used in current environment.
*/
public boolean isDataProfileCompatible(@NonNull DataProfile dataProfile) {
- if (dataProfile == null) {
- return false;
- }
-
if (dataProfile.getApnSetting() == null && dataProfile.getTrafficDescriptor() != null) {
// A traffic descriptor only data profile can be always used. Traffic descriptors are
// always generated on the fly instead loaded from the database.
@@ -1224,7 +1209,10 @@
pw.println("Preferred data profile from db=" + getPreferredDataProfileFromDb());
pw.println("Preferred data profile from config=" + getPreferredDataProfileFromConfig());
pw.println("Preferred data profile set id=" + mPreferredDataProfileSetId);
- pw.println("Last internet data profile=" + mLastInternetDataProfile);
+ pw.println("Last internet data profile for=");
+ pw.increaseIndent();
+ mLastInternetDataProfiles.snapshot().forEach((key, value) -> pw.println(key + ":" + value));
+ pw.decreaseIndent();
pw.println("Initial attach data profile=" + mInitialAttachDataProfile);
pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting(
TelephonyManager.NETWORK_TYPE_LTE));
diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java
index 1fdc182..7454d01 100644
--- a/src/java/com/android/internal/telephony/data/DataRetryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java
@@ -214,7 +214,7 @@
public final @Nullable NetworkRequestList networkRequestList;
/**
- * @param dataNetwork The data network that is being throttled for handover retry. Should be
+ * The data network that is being throttled for handover retry. Should be
* {@code null} when retryType is {@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION}.
*/
public final @Nullable DataNetwork dataNetwork;
@@ -487,7 +487,7 @@
* @param cause Fail cause from previous setup data request.
* @return {@code true} if the retry rule can be matched.
*/
- public boolean canBeMatched(@NonNull @NetCapability int networkCapability,
+ public boolean canBeMatched(@NetCapability int networkCapability,
@DataFailureCause int cause) {
if (!mFailCauses.isEmpty() && !mFailCauses.contains(cause)) {
return false;
@@ -628,13 +628,13 @@
* @return Retry state in string format.
*/
public static String retryStateToString(@DataRetryState int retryState) {
- switch (retryState) {
- case RETRY_STATE_NOT_RETRIED: return "NOT_RETRIED";
- case RETRY_STATE_FAILED: return "FAILED";
- case RETRY_STATE_SUCCEEDED: return "SUCCEEDED";
- case RETRY_STATE_CANCELLED: return "CANCELLED";
- default: return "Unknown(" + retryState + ")";
- }
+ return switch (retryState) {
+ case RETRY_STATE_NOT_RETRIED -> "NOT_RETRIED";
+ case RETRY_STATE_FAILED -> "FAILED";
+ case RETRY_STATE_SUCCEEDED -> "SUCCEEDED";
+ case RETRY_STATE_CANCELLED -> "CANCELLED";
+ default -> "Unknown(" + retryState + ")";
+ };
}
/**
@@ -1168,7 +1168,7 @@
// when unthrottling happens, we still want to retry and we'll need
// a type there so we know what to retry. Using RETRY_TYPE_NONE
// ThrottleStatus is just for API backwards compatibility reason.
- updateThrottleStatus(dataProfile, requestList, null,
+ throttleDataProfile(dataProfile, requestList, null,
ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE);
return;
} else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) {
@@ -1180,7 +1180,7 @@
.setDataProfile(dataProfile)
.setTransport(transport)
.build();
- updateThrottleStatus(dataProfile, requestList, null,
+ throttleDataProfile(dataProfile, requestList, null,
ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport,
dataSetupRetryEntry.retryElapsedTime);
schedule(dataSetupRetryEntry);
@@ -1298,7 +1298,7 @@
// when unthrottling happens, we still want to retry and we'll need
// a type there so we know what to retry. Using RETRY_TYPE_NONE
// ThrottleStatus is just for API backwards compatibility reason.
- updateThrottleStatus(dataNetwork.getDataProfile(),
+ throttleDataProfile(dataNetwork.getDataProfile(),
dataNetwork.getAttachedNetworkRequestList(), dataNetwork,
ThrottleStatus.RETRY_TYPE_HANDOVER, targetTransport, Long.MAX_VALUE);
} else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) {
@@ -1308,7 +1308,7 @@
.setDataNetwork(dataNetwork)
.build();
- updateThrottleStatus(dataNetwork.getDataProfile(),
+ throttleDataProfile(dataNetwork.getDataProfile(),
dataNetwork.getAttachedNetworkRequestList(), dataNetwork,
ThrottleStatus.RETRY_TYPE_HANDOVER, targetTransport,
dataHandoverRetryEntry.retryElapsedTime);
@@ -1534,7 +1534,7 @@
* @param expirationTime The expiration time of data throttling. This is the time retrieved from
* {@link SystemClock#elapsedRealtime()}.
*/
- private void updateThrottleStatus(@NonNull DataProfile dataProfile,
+ private void throttleDataProfile(@NonNull DataProfile dataProfile,
@Nullable NetworkRequestList networkRequestList,
@Nullable DataNetwork dataNetwork, @RetryType int retryType,
@TransportType int transport, @ElapsedRealtimeLong long expirationTime) {
@@ -1565,21 +1565,7 @@
? ThrottleStatus.RETRY_TYPE_NONE : retryType;
// Report to the clients.
- final List<ThrottleStatus> throttleStatusList = new ArrayList<>();
- if (dataProfile.getApnSetting() != null) {
- throttleStatusList.addAll(dataProfile.getApnSetting().getApnTypes().stream()
- .map(apnType -> new ThrottleStatus.Builder()
- .setApnType(apnType)
- .setRetryType(dataRetryType)
- .setSlotIndex(mPhone.getPhoneId())
- .setThrottleExpiryTimeMillis(expirationTime)
- .setTransportType(transport)
- .build())
- .collect(Collectors.toList()));
- }
-
- mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
- () -> callback.onThrottleStatusChanged(throttleStatusList)));
+ notifyThrottleStatus(dataProfile, expirationTime, dataRetryType, transport);
}
/**
@@ -1650,23 +1636,9 @@
// Make it final so it can be used in the lambda function below.
final int dataRetryType = retryType;
- if (unthrottledProfile != null && unthrottledProfile.getApnSetting() != null) {
- unthrottledProfile.getApnSetting().setPermanentFailed(false);
- throttleStatusList.addAll(unthrottledProfile.getApnSetting().getApnTypes().stream()
- .map(apnType -> new ThrottleStatus.Builder()
- .setApnType(apnType)
- .setSlotIndex(mPhone.getPhoneId())
- .setNoThrottle()
- .setRetryType(dataRetryType)
- .setTransportType(transport)
- .build())
- .collect(Collectors.toList()));
- }
-
- mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
- () -> callback.onThrottleStatusChanged(throttleStatusList)));
-
if (unthrottledProfile != null) {
+ notifyThrottleStatus(unthrottledProfile, ThrottleStatus.Builder.NO_THROTTLE_EXPIRY_TIME,
+ dataRetryType, transport);
// cancel pending retries since we will soon schedule an immediate retry
cancelRetriesForDataProfile(unthrottledProfile, transport);
}
@@ -1799,6 +1771,60 @@
&& ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork
&& entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED)
.forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED));
+
+ long now = SystemClock.elapsedRealtime();
+ DataThrottlingEntry dataUnThrottlingEntry = mDataThrottlingEntries.stream()
+ .filter(entry -> dataNetwork == entry.dataNetwork
+ && entry.expirationTimeMillis > now).findAny().orElse(null);
+ if (dataUnThrottlingEntry == null) {
+ return;
+ }
+ log("onCancelPendingHandoverRetry removed throttling entry:" + dataUnThrottlingEntry);
+ DataProfile unThrottledProfile =
+ dataUnThrottlingEntry.dataNetwork.getDataProfile();
+ final int transport = dataUnThrottlingEntry.transport;
+
+ notifyThrottleStatus(unThrottledProfile, ThrottleStatus.Builder.NO_THROTTLE_EXPIRY_TIME,
+ ThrottleStatus.RETRY_TYPE_HANDOVER, transport);
+ mDataThrottlingEntries.removeIf(entry -> dataNetwork == entry.dataNetwork);
+ }
+
+ /**
+ * Notify listeners of throttle status for a given data profile
+ *
+ * @param dataProfile Data profile for this throttling status notification
+ * @param expirationTime Expiration time of throttling status. {@link
+ * ThrottleStatus.Builder#NO_THROTTLE_EXPIRY_TIME} indicates un-throttling.
+ * @param dataRetryType Retry type of this throttling notification.
+ * @param transportType Transport type of this throttling notification.
+ */
+ private void notifyThrottleStatus(
+ @NonNull DataProfile dataProfile, long expirationTime, @RetryType int dataRetryType,
+ @TransportType int transportType) {
+ if (dataProfile.getApnSetting() != null) {
+ final boolean unThrottled =
+ expirationTime == ThrottleStatus.Builder.NO_THROTTLE_EXPIRY_TIME;
+ if (unThrottled) {
+ dataProfile.getApnSetting().setPermanentFailed(false);
+ }
+ final List<ThrottleStatus> throttleStatusList = new ArrayList<>(
+ dataProfile.getApnSetting().getApnTypes().stream()
+ .map(apnType -> {
+ ThrottleStatus.Builder builder = new ThrottleStatus.Builder()
+ .setApnType(apnType)
+ .setSlotIndex(mPhone.getPhoneId())
+ .setRetryType(dataRetryType)
+ .setTransportType(transportType);
+ if (unThrottled) {
+ builder.setNoThrottle();
+ } else {
+ builder.setThrottleExpiryTimeMillis(expirationTime);
+ }
+ return builder.build();
+ }).toList());
+ mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
+ () -> callback.onThrottleStatusChanged(throttleStatusList)));
+ }
}
/**
@@ -1840,22 +1866,15 @@
* @return The reason in string format.
*/
private static @NonNull String resetReasonToString(int reason) {
- switch (reason) {
- case RESET_REASON_DATA_PROFILES_CHANGED:
- return "DATA_PROFILES_CHANGED";
- case RESET_REASON_RADIO_ON:
- return "RADIO_ON";
- case RESET_REASON_MODEM_RESTART:
- return "MODEM_RESTART";
- case RESET_REASON_DATA_SERVICE_BOUND:
- return "DATA_SERVICE_BOUND";
- case RESET_REASON_DATA_CONFIG_CHANGED:
- return "DATA_CONFIG_CHANGED";
- case RESET_REASON_TAC_CHANGED:
- return "TAC_CHANGED";
- default:
- return "UNKNOWN(" + reason + ")";
- }
+ return switch (reason) {
+ case RESET_REASON_DATA_PROFILES_CHANGED -> "DATA_PROFILES_CHANGED";
+ case RESET_REASON_RADIO_ON -> "RADIO_ON";
+ case RESET_REASON_MODEM_RESTART -> "MODEM_RESTART";
+ case RESET_REASON_DATA_SERVICE_BOUND -> "DATA_SERVICE_BOUND";
+ case RESET_REASON_DATA_CONFIG_CHANGED -> "DATA_CONFIG_CHANGED";
+ case RESET_REASON_TAC_CHANGED -> "TAC_CHANGED";
+ default -> "UNKNOWN(" + reason + ")";
+ };
}
/**
diff --git a/src/java/com/android/internal/telephony/data/DataServiceManager.java b/src/java/com/android/internal/telephony/data/DataServiceManager.java
index ee66a6a..a71bd10 100644
--- a/src/java/com/android/internal/telephony/data/DataServiceManager.java
+++ b/src/java/com/android/internal/telephony/data/DataServiceManager.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony.data;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import android.annotation.NonNull;
@@ -61,6 +60,7 @@
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.telephony.Rlog;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -82,17 +82,12 @@
private static final int EVENT_BIND_DATA_SERVICE = 1;
- private static final int EVENT_WATCHDOG_TIMEOUT = 2;
-
- private static final long REQUEST_UNRESPONDED_TIMEOUT = 10 * MINUTE_IN_MILLIS; // 10 mins
-
private static final long CHANGE_PERMISSION_TIMEOUT_MS = 15 * SECOND_IN_MILLIS; // 15 secs
private final Phone mPhone;
private final String mTag;
- private final CarrierConfigManager mCarrierConfigManager;
private final AppOpsManager mAppOps;
private final LegacyPermissionManager mPermissionManager;
@@ -102,8 +97,6 @@
private IDataService mIDataService;
- private DataServiceManagerDeathRecipient mDeathRecipient;
-
private final RegistrantList mServiceBindingChangedRegistrants = new RegistrantList();
private final Map<IBinder, Message> mMessageMap = new ConcurrentHashMap<>();
@@ -118,7 +111,7 @@
private String mLastBoundPackageName;
- private List<DataCallResponse> mLastDataCallResponseList = Collections.EMPTY_LIST;
+ private List<DataCallResponse> mLastDataCallResponseList = new ArrayList<>();
private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient {
@Override
@@ -137,7 +130,7 @@
mMessageMap.clear();
// Tear down all connections
- mLastDataCallResponseList = Collections.EMPTY_LIST;
+ mLastDataCallResponseList = new ArrayList<>();
mDataCallListChangedRegistrants.notifyRegistrants(
new AsyncResult(null, Collections.EMPTY_LIST, null));
}
@@ -209,13 +202,11 @@
public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) log("onServiceConnected: " + name);
mIDataService = IDataService.Stub.asInterface(service);
- mDeathRecipient = new DataServiceManagerDeathRecipient();
mBound = true;
mLastBoundPackageName = getDataServicePackageName();
- removeMessages(EVENT_WATCHDOG_TIMEOUT);
try {
- service.linkToDeath(mDeathRecipient, 0);
+ service.linkToDeath(new DataServiceManagerDeathRecipient(), 0);
mIDataService.createDataServiceProvider(mPhone.getPhoneId());
mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(),
new DataServiceCallbackWrapper("dataCallListChanged"));
@@ -230,7 +221,6 @@
@Override
public void onServiceDisconnected(ComponentName name) {
if (DBG) log("onServiceDisconnected");
- removeMessages(EVENT_WATCHDOG_TIMEOUT);
mIDataService = null;
mBound = false;
mServiceBindingChangedRegistrants.notifyResult(false);
@@ -257,7 +247,6 @@
log("onSetupDataCallComplete. resultCode = " + resultCode + ", response = "
+ response);
}
- removeMessages(EVENT_WATCHDOG_TIMEOUT, DataServiceCallbackWrapper.this);
Message msg = mMessageMap.remove(asBinder());
if (msg != null) {
msg.getData().putParcelable(DATA_CALL_RESPONSE, response);
@@ -270,7 +259,6 @@
@Override
public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) {
if (DBG) log("onDeactivateDataCallComplete. resultCode = " + resultCode);
- removeMessages(EVENT_WATCHDOG_TIMEOUT, DataServiceCallbackWrapper.this);
Message msg = mMessageMap.remove(asBinder());
sendCompleteMessage(msg, resultCode);
}
@@ -326,7 +314,7 @@
@Override
public void onDataCallListChanged(List<DataCallResponse> dataCallList) {
mLastDataCallResponseList =
- dataCallList != null ? dataCallList : Collections.EMPTY_LIST;
+ dataCallList != null ? dataCallList : new ArrayList<>();
mDataCallListChangedRegistrants.notifyRegistrants(
new AsyncResult(null, dataCallList, null));
}
@@ -334,7 +322,6 @@
@Override
public void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode) {
if (DBG) log("onHandoverStarted. resultCode = " + resultCode);
- removeMessages(EVENT_WATCHDOG_TIMEOUT, DataServiceCallbackWrapper.this);
Message msg = mMessageMap.remove(asBinder());
sendCompleteMessage(msg, resultCode);
}
@@ -342,7 +329,6 @@
@Override
public void onHandoverCancelled(@DataServiceCallback.ResultCode int resultCode) {
if (DBG) log("onHandoverCancelled. resultCode = " + resultCode);
- removeMessages(EVENT_WATCHDOG_TIMEOUT, DataServiceCallbackWrapper.this);
Message msg = mMessageMap.remove(asBinder());
sendCompleteMessage(msg, resultCode);
}
@@ -383,8 +369,8 @@
mTag = "DSM-" + (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN ? "C-"
: "I-") + mPhone.getPhoneId();
mBound = false;
- mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
- Context.CARRIER_CONFIG_SERVICE);
+ CarrierConfigManager carrierConfigManager = phone.getContext().getSystemService(
+ CarrierConfigManager.class);
// NOTE: Do NOT use AppGlobals to retrieve the permission manager; AppGlobals
// caches the service instance, but we need to explicitly request a new service
// so it can be mocked out for tests
@@ -393,17 +379,18 @@
mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE);
// Callback is executed in handler thread to directly handle config change.
- mCarrierConfigManager.registerCarrierConfigChangeListener(this::post,
- (slotIndex, subId, carrierId, specificCarrierId) -> {
- if (slotIndex == mPhone.getPhoneId()) {
- // We should wait for carrier config changed event because the
- // target binding package name can come from the carrier config.
- // Note that we still get this event even when SIM is absent.
- if (DBG) log("Carrier config changed. Try to bind data service.");
- rebindDataService();
- }
- });
-
+ if (carrierConfigManager != null) {
+ carrierConfigManager.registerCarrierConfigChangeListener(this::post,
+ (slotIndex, subId, carrierId, specificCarrierId) -> {
+ if (slotIndex == mPhone.getPhoneId()) {
+ // We should wait for carrier config changed event because the
+ // target binding package name can come from the carrier config.
+ // Note that we still get this event even when SIM is absent.
+ if (DBG) log("Carrier config changed. Try to bind data service.");
+ rebindDataService();
+ }
+ });
+ }
PhoneConfigurationManager.registerForMultiSimConfigChange(
this, EVENT_BIND_DATA_SERVICE, null);
@@ -417,29 +404,13 @@
*/
@Override
public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_BIND_DATA_SERVICE:
- rebindDataService();
- break;
- case EVENT_WATCHDOG_TIMEOUT:
- handleRequestUnresponded((DataServiceCallbackWrapper) msg.obj);
- break;
- default:
- loge("Unhandled event " + msg.what);
+ if (msg.what == EVENT_BIND_DATA_SERVICE) {
+ rebindDataService();
+ } else {
+ loge("Unhandled event " + msg.what);
}
}
- private void handleRequestUnresponded(DataServiceCallbackWrapper callback) {
- String message = "Request " + callback.getTag() + " unresponded on transport "
- + AccessNetworkConstants.transportTypeToString(mTransportType) + " in "
- + REQUEST_UNRESPONDED_TIMEOUT / 1000 + " seconds.";
- log(message);
- // Using fixed UUID to avoid duplicate bugreport notification
- AnomalyReporter.reportAnomaly(
- UUID.fromString("f5d5cbe6-9bd6-4009-b764-42b1b649b1de"),
- message, mPhone.getCarrierId());
- }
-
private void unbindDataService() {
// Start by cleaning up all packages that *shouldn't* have permissions.
revokePermissionsFromUnusedDataServices();
@@ -473,7 +444,7 @@
return;
}
- Intent intent = null;
+ Intent intent;
String className = getDataServiceClassName();
if (TextUtils.isEmpty(className)) {
intent = new Intent(DataService.SERVICE_INTERFACE);
@@ -512,7 +483,8 @@
bindDataService(packageName);
}
- private @NonNull Set<String> getAllDataServicePackageNames() {
+ @NonNull
+ private Set<String> getAllDataServicePackageNames() {
// Cowardly using the public PackageManager interface here.
// Note: This matches only packages that were installed on the system image. If we ever
// expand the permissions model to allow CarrierPrivileged packages, then this will need
@@ -540,7 +512,7 @@
/**
* Get the data service package by transport type.
- *
+ * <p>
* When we bind to a DataService package, we need to revoke permissions from stale
* packages; we need to exclude data packages for all transport types, so we need to
* to be able to query by transport type.
@@ -552,21 +524,19 @@
String packageName;
int resourceId;
String carrierConfig;
-
switch (transportType) {
- case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
+ case AccessNetworkConstants.TRANSPORT_TYPE_WWAN -> {
resourceId = com.android.internal.R.string.config_wwan_data_service_package;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING;
- break;
- case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
+ }
+ case AccessNetworkConstants.TRANSPORT_TYPE_WLAN -> {
resourceId = com.android.internal.R.string.config_wlan_data_service_package;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING;
- break;
- default:
- throw new IllegalStateException("Transport type not WWAN or WLAN. type="
- + AccessNetworkConstants.transportTypeToString(mTransportType));
+ }
+ default -> throw new IllegalStateException("Transport type not WWAN or WLAN. type="
+ + AccessNetworkConstants.transportTypeToString(mTransportType));
}
// Read package name from resource overlay
@@ -604,19 +574,18 @@
int resourceId;
String carrierConfig;
switch (transportType) {
- case AccessNetworkConstants.TRANSPORT_TYPE_WWAN:
+ case AccessNetworkConstants.TRANSPORT_TYPE_WWAN -> {
resourceId = com.android.internal.R.string.config_wwan_data_service_class;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WWAN_CLASS_OVERRIDE_STRING;
- break;
- case AccessNetworkConstants.TRANSPORT_TYPE_WLAN:
+ }
+ case AccessNetworkConstants.TRANSPORT_TYPE_WLAN -> {
resourceId = com.android.internal.R.string.config_wlan_data_service_class;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WLAN_CLASS_OVERRIDE_STRING;
- break;
- default:
- throw new IllegalStateException("Transport type not WWAN or WLAN. type="
- + transportType);
+ }
+ default -> throw new IllegalStateException("Transport type not WWAN or WLAN. type="
+ + transportType);
}
// Read package name from resource overlay
@@ -680,8 +649,6 @@
mMessageMap.put(callback.asBinder(), onCompleteMessage);
}
try {
- sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
- REQUEST_UNRESPONDED_TIMEOUT);
mIDataService.setupDataCall(mPhone.getPhoneId(), accessNetworkType, dataProfile,
isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
trafficDescriptor, matchAllRuleAllowed, callback);
@@ -720,8 +687,6 @@
mMessageMap.put(callback.asBinder(), onCompleteMessage);
}
try {
- sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
- REQUEST_UNRESPONDED_TIMEOUT);
mIDataService.deactivateDataCall(mPhone.getPhoneId(), cid, reason, callback);
} catch (RemoteException e) {
loge("Cannot invoke deactivateDataCall on data service.");
@@ -732,13 +697,13 @@
/**
* Indicates that a handover has begun. This is called on the source transport.
- *
+ * <p>
* Any resources being transferred cannot be released while a
* handover is underway.
- *
+ * <p>
* If a handover was unsuccessful, then the framework calls DataServiceManager#cancelHandover.
* The target transport retains ownership over any of the resources being transferred.
- *
+ * <p>
* If a handover was successful, the framework calls DataServiceManager#deactivateDataCall with
* reason HANDOVER. The target transport now owns the transferred resources and is
* responsible for releasing them.
@@ -756,13 +721,9 @@
DataServiceCallbackWrapper callback =
new DataServiceCallbackWrapper("startHandover");
- if (onCompleteMessage != null) {
- mMessageMap.put(callback.asBinder(), onCompleteMessage);
- }
+ mMessageMap.put(callback.asBinder(), onCompleteMessage);
try {
- sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
- REQUEST_UNRESPONDED_TIMEOUT);
mIDataService.startHandover(mPhone.getPhoneId(), cid, callback);
} catch (RemoteException e) {
loge("Cannot invoke startHandover on data service.");
@@ -774,7 +735,7 @@
/**
* Indicates that a handover was cancelled after a call to DataServiceManager#startHandover.
* This is called on the source transport.
- *
+ * <p>
* Since the handover was unsuccessful, the source transport retains ownership over any of
* the resources being transferred and is still responsible for releasing them.
*
@@ -791,13 +752,9 @@
DataServiceCallbackWrapper callback =
new DataServiceCallbackWrapper("cancelHandover");
- if (onCompleteMessage != null) {
- mMessageMap.put(callback.asBinder(), onCompleteMessage);
- }
+ mMessageMap.put(callback.asBinder(), onCompleteMessage);
try {
- sendMessageDelayed(obtainMessage(EVENT_WATCHDOG_TIMEOUT, callback),
- REQUEST_UNRESPONDED_TIMEOUT);
mIDataService.cancelHandover(mPhone.getPhoneId(), cid, callback);
} catch (RemoteException e) {
loge("Cannot invoke cancelHandover on data service.");
@@ -894,9 +851,7 @@
mIDataService.requestDataCallList(mPhone.getPhoneId(), callback);
} catch (RemoteException e) {
loge("Cannot invoke requestDataCallList on data service.");
- if (callback != null) {
- mMessageMap.remove(callback.asBinder());
- }
+ mMessageMap.remove(callback.asBinder());
sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
}
}
@@ -937,17 +892,6 @@
}
/**
- * Unregister for apn unthrottled event
- *
- * @param h The handler
- */
- public void unregisterForApnUnthrottled(Handler h) {
- if (h != null) {
- mApnUnthrottledRegistrants.remove(h);
- }
- }
-
- /**
* Request data network validation.
*
* <p>Validates a given data network to ensure that the network can work properly.
@@ -981,9 +925,7 @@
mIDataService.requestNetworkValidation(mPhone.getPhoneId(), cid, callback);
} catch (RemoteException e) {
loge("Cannot invoke requestNetworkValidation on data service.");
- if (callback != null) {
- mMessageMap.remove(callback.asBinder());
- }
+ mMessageMap.remove(callback.asBinder());
sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE);
}
}
@@ -1005,17 +947,6 @@
}
}
- /**
- * Unregister for data service binding status changed event.
- *
- * @param h The handler
- */
- public void unregisterForServiceBindingChanged(Handler h) {
- if (h != null) {
- mServiceBindingChangedRegistrants.remove(h);
- }
- }
-
private void log(String s) {
Rlog.d(mTag, s);
}
diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
index ee8890a..ec6b40f 100644
--- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
@@ -73,12 +73,11 @@
value = {
RECOVERY_ACTION_GET_DATA_CALL_LIST,
RECOVERY_ACTION_CLEANUP,
- RECOVERY_ACTION_REREGISTER,
RECOVERY_ACTION_RADIO_RESTART,
RECOVERY_ACTION_RESET_MODEM
})
@Retention(RetentionPolicy.SOURCE)
- public @interface RecoveryAction {};
+ public @interface RecoveryAction {}
/* DataStallRecoveryManager queries RIL for link properties (IP addresses, DNS server addresses
* etc) using RIL_REQUEST_GET_DATA_CALL_LIST. This will help in cases where the data stall
@@ -92,16 +91,6 @@
*/
public static final int RECOVERY_ACTION_CLEANUP = 1;
- /**
- * Add the RECOVERY_ACTION_REREGISTER to align the RecoveryActions between
- * DataStallRecoveryManager and atoms.proto. In Android T, This action will not process because
- * the boolean array for skip recovery action is default true in carrier config setting.
- *
- * @deprecated Do not use.
- */
- @java.lang.Deprecated
- public static final int RECOVERY_ACTION_REREGISTER = 2;
-
/* DataStallRecoveryManager will request ServiceStateTracker to send RIL_REQUEST_RADIO_POWER
* to restart radio. It will restart the radio and re-attch to the network.
*/
@@ -121,9 +110,9 @@
RECOVERED_REASON_USER
})
@Retention(RetentionPolicy.SOURCE)
- public @interface RecoveredReason {};
+ public @interface RecoveredReason {}
- /** The reason when data stall recovered. */
+ // The reason when data stall recovered.
/** The data stall not recovered yet. */
private static final int RECOVERED_REASON_NONE = 0;
/** The data stall recovered by our DataStallRecoveryManager. */
@@ -224,12 +213,13 @@
Settings.Global.DSRM_DURATION_MILLIS);
- private DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;
+ private final DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;
private final DataStallRecoveryStats mStats;
/** The number of milliseconds to wait for the DSRM prediction to complete. */
- private @ElapsedRealtimeLong long mPredictWaitingMillis = 0L;
+ @ElapsedRealtimeLong
+ private long mPredictWaitingMillis = 0L;
/**
* The data stall recovery manager callback. Note this is only used for passing information
@@ -476,9 +466,8 @@
// Copy the values from the durationMillisArray array to the
// mDataStallRecoveryDelayMillisArray array.
- for (int i = 0; i < minLength; i++) {
- mDataStallRecoveryDelayMillisArray[i] = durationMillisArray[i];
- }
+ System.arraycopy(durationMillisArray, 0, mDataStallRecoveryDelayMillisArray,
+ 0, minLength);
log("DataStallRecoveryDelayMillis: "
+ Arrays.toString(mDataStallRecoveryDelayMillisArray));
mPredictWaitingMillis = DSRM_PREDICT_WAITING_MILLIS;
@@ -872,7 +861,7 @@
isFirstValidationAfterDoRecovery, timeDurationOfCurrentAction);
logl(
"data stall: "
- + (isFirstDataStall == true ? "start" : isValid == false ? "in process" : "end")
+ + (isFirstDataStall ? "start" : !isValid ? "in process" : "end")
+ ", lastaction="
+ recoveryActionToString(mLastAction)
+ ", isRecovered="
@@ -965,18 +954,13 @@
* @return The recovered reason in string format.
*/
private static @NonNull String recoveredReasonToString(@RecoveredReason int reason) {
- switch (reason) {
- case RECOVERED_REASON_NONE:
- return "RECOVERED_REASON_NONE";
- case RECOVERED_REASON_DSRM:
- return "RECOVERED_REASON_DSRM";
- case RECOVERED_REASON_MODEM:
- return "RECOVERED_REASON_MODEM";
- case RECOVERED_REASON_USER:
- return "RECOVERED_REASON_USER";
- default:
- return "Unknown(" + reason + ")";
- }
+ return switch (reason) {
+ case RECOVERED_REASON_NONE -> "RECOVERED_REASON_NONE";
+ case RECOVERED_REASON_DSRM -> "RECOVERED_REASON_DSRM";
+ case RECOVERED_REASON_MODEM -> "RECOVERED_REASON_MODEM";
+ case RECOVERED_REASON_USER -> "RECOVERED_REASON_USER";
+ default -> "Unknown(" + reason + ")";
+ };
}
/**
@@ -1005,18 +989,13 @@
* @return The recovery action in string format.
*/
private static @NonNull String recoveryActionToString(@RecoveryAction int action) {
- switch (action) {
- case RECOVERY_ACTION_GET_DATA_CALL_LIST:
- return "RECOVERY_ACTION_GET_DATA_CALL_LIST";
- case RECOVERY_ACTION_CLEANUP:
- return "RECOVERY_ACTION_CLEANUP";
- case RECOVERY_ACTION_RADIO_RESTART:
- return "RECOVERY_ACTION_RADIO_RESTART";
- case RECOVERY_ACTION_RESET_MODEM:
- return "RECOVERY_ACTION_RESET_MODEM";
- default:
- return "Unknown(" + action + ")";
- }
+ return switch (action) {
+ case RECOVERY_ACTION_GET_DATA_CALL_LIST -> "RECOVERY_ACTION_GET_DATA_CALL_LIST";
+ case RECOVERY_ACTION_CLEANUP -> "RECOVERY_ACTION_CLEANUP";
+ case RECOVERY_ACTION_RADIO_RESTART -> "RECOVERY_ACTION_RADIO_RESTART";
+ case RECOVERY_ACTION_RESET_MODEM -> "RECOVERY_ACTION_RESET_MODEM";
+ default -> "Unknown(" + action + ")";
+ };
}
/**
diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java
index cca6deb..49e54e7 100644
--- a/src/java/com/android/internal/telephony/data/DataUtils.java
+++ b/src/java/com/android/internal/telephony/data/DataUtils.java
@@ -36,7 +36,6 @@
import android.telephony.data.ApnSetting.ApnType;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataCallResponse.LinkStatus;
-import android.telephony.data.DataProfile;
import android.telephony.ims.feature.ImsFeature;
import android.util.ArrayMap;
@@ -49,7 +48,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -385,25 +383,6 @@
}
/**
- * Get the highest priority supported network capability from the specified data profile.
- *
- * @param dataConfigManager The data config that contains network priority information.
- * @param dataProfile The data profile
- * @return The highest priority network capability. -1 if cannot find one.
- */
- public static @NetCapability int getHighestPriorityNetworkCapabilityFromDataProfile(
- @NonNull DataConfigManager dataConfigManager, @NonNull DataProfile dataProfile) {
- if (dataProfile.getApnSetting() == null
- || dataProfile.getApnSetting().getApnTypes().isEmpty()) return -1;
- return dataProfile.getApnSetting().getApnTypes().stream()
- .map(DataUtils::apnTypeToNetworkCapability)
- .sorted(Comparator.comparing(dataConfigManager::getNetworkCapabilityPriority)
- .reversed())
- .collect(Collectors.toList())
- .get(0);
- }
-
- /**
* Group the network requests into several list that contains the same network capabilities.
*
* @param networkRequestList The provided network requests.
diff --git a/src/java/com/android/internal/telephony/data/KeepaliveTracker.java b/src/java/com/android/internal/telephony/data/KeepaliveTracker.java
index f9139ec..0a01339 100644
--- a/src/java/com/android/internal/telephony/data/KeepaliveTracker.java
+++ b/src/java/com/android/internal/telephony/data/KeepaliveTracker.java
@@ -254,17 +254,12 @@
* @return The socket alive error.
*/
private int keepaliveStatusErrorToPacketKeepaliveError(int error) {
- switch(error) {
- case KeepaliveStatus.ERROR_NONE:
- return SocketKeepalive.SUCCESS;
- case KeepaliveStatus.ERROR_UNSUPPORTED:
- return SocketKeepalive.ERROR_UNSUPPORTED;
- case KeepaliveStatus.ERROR_NO_RESOURCES:
- return SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
- case KeepaliveStatus.ERROR_UNKNOWN:
- default:
- return SocketKeepalive.ERROR_HARDWARE_ERROR;
- }
+ return switch (error) {
+ case KeepaliveStatus.ERROR_NONE -> SocketKeepalive.SUCCESS;
+ case KeepaliveStatus.ERROR_UNSUPPORTED -> SocketKeepalive.ERROR_UNSUPPORTED;
+ case KeepaliveStatus.ERROR_NO_RESOURCES -> SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
+ default -> SocketKeepalive.ERROR_HARDWARE_ERROR;
+ };
}
/**
diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java
index de8c48c..b92a590 100644
--- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java
+++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java
@@ -30,6 +30,7 @@
import android.os.AsyncResult;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.Looper;
import android.os.Message;
import android.os.OutcomeReceiver;
import android.preference.PreferenceManager;
@@ -165,7 +166,6 @@
private final Phone mPhone;
private final TelephonyFacade mTelephonyFacade;
private final TelephonyManager mTelephonyManager;
- private final ConnectivityManager mConnectivityManager;
private final LocalLog mLocalLog = new LocalLog(512);
private boolean mScreenOn = false;
private boolean mIsOnDefaultRoute = false;
@@ -178,29 +178,29 @@
private long mRxBytesDeltaAcc;
private ModemActivityInfo mLastModemActivityInfo = null;
- private final TelephonyCallback mTelephonyCallback = new TelephonyCallbackImpl();
private int mSignalStrengthDbm;
private int mSignalLevel;
private int mDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private int mTac;
@NonNull private String mPlmn = UNKNOWN_PLMN;
private NetworkCapabilities mNetworkCapabilities;
- private NetworkBandwidth mPlaceholderNetwork;
+ private final NetworkBandwidth mPlaceholderNetwork;
private long mFilterUpdateTimeMs;
private int mBandwidthUpdateSignalDbm = -1;
private int mBandwidthUpdateSignalLevel = -1;
private int mBandwidthUpdateDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
private String mBandwidthUpdatePlmn = UNKNOWN_PLMN;
- private BandwidthState mTxState = new BandwidthState(LINK_TX);
- private BandwidthState mRxState = new BandwidthState(LINK_RX);
+ private final BandwidthState mTxState = new BandwidthState(LINK_TX);
+ private final BandwidthState mRxState = new BandwidthState(LINK_RX);
private long mLastPlmnOrRatChangeTimeMs;
private long mLastDrsOrRatChangeTimeMs;
private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
/** Link bandwidth estimator callbacks. */
- private final @NonNull Set<LinkBandwidthEstimatorCallback> mLinkBandwidthEstimatorCallbacks =
+ @NonNull
+ private final Set<LinkBandwidthEstimatorCallback> mLinkBandwidthEstimatorCallbacks =
new ArraySet<>();
/**
@@ -270,14 +270,14 @@
private final OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException>
mOutcomeReceiver =
- new OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException>() {
+ new OutcomeReceiver<>() {
@Override
public void onResult(ModemActivityInfo result) {
obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, result).sendToTarget();
}
@Override
- public void onError(TelephonyManager.ModemActivityInfoException e) {
+ public void onError(@NonNull TelephonyManager.ModemActivityInfoException e) {
Rlog.e(TAG, "error reading modem stats:" + e);
obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, null).sendToTarget();
}
@@ -296,20 +296,27 @@
}
};
- public LinkBandwidthEstimator(Phone phone, TelephonyFacade telephonyFacade) {
+ public LinkBandwidthEstimator(Phone phone, Looper looper, TelephonyFacade telephonyFacade) {
+ super(looper);
mPhone = phone;
mTelephonyFacade = telephonyFacade;
mTelephonyManager = phone.getContext()
.getSystemService(TelephonyManager.class)
.createForSubscriptionId(phone.getSubId());
- mConnectivityManager = phone.getContext().getSystemService(ConnectivityManager.class);
DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
Context.DISPLAY_SERVICE);
- dm.registerDisplayListener(mDisplayListener, null);
+ if (dm != null) {
+ dm.registerDisplayListener(mDisplayListener, null);
+ }
handleScreenStateChanged(isScreenOn());
- mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
+
+ ConnectivityManager cm = phone.getContext()
+ .getSystemService(ConnectivityManager.class);
+ if (cm != null) {
+ cm.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
+ }
mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this),
- mTelephonyCallback);
+ new TelephonyCallbackImpl());
mPlaceholderNetwork = new NetworkBandwidth(UNKNOWN_PLMN);
initAvgBwPerRatTable();
registerNrStateFrequencyChange();
@@ -382,6 +389,7 @@
// the screen is turned off transiently such as due to the proximity sensor.
final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService(
Context.DISPLAY_SERVICE);
+ if (dm == null) return false;
Display[] displays = dm.getDisplays();
if (displays != null) {
@@ -432,6 +440,7 @@
handleTrafficStatsPollConditionChanged();
}
+ @SuppressWarnings("unchecked")
private void handleDrsOrRatChanged(AsyncResult ar) {
Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>) ar.result;
logd("DrsOrRatChanged dataRegState " + drsRatPair.first + " rilRat " + drsRatPair.second);
@@ -729,7 +738,7 @@
return;
}
long filterOutKbps = (long) mFilterKbps * alpha
- + filterInKbps * FILTER_SCALE - filterInKbps * alpha;
+ + (long) filterInKbps * FILTER_SCALE - (long) filterInKbps * alpha;
filterOutKbps = filterOutKbps / FILTER_SCALE;
mFilterKbps = (int) Math.min(filterOutKbps, Integer.MAX_VALUE);
@@ -877,8 +886,8 @@
StringBuilder sb = new StringBuilder();
logd(sb.append(mLink)
- .append(" sampKbps ").append(mBwSampleKbps)
- .append(" filtKbps ").append(mFilterKbps)
+ .append(" sampleKbps ").append(mBwSampleKbps)
+ .append(" filterKbps ").append(mFilterKbps)
.append(" reportKbps ").append(mLastReportedBwKbps)
.append(" avgUsedKbps ").append(mAvgUsedKbps)
.append(" csKbps ").append(mStaticBwKbps)
@@ -944,7 +953,8 @@
/**
* @return The data activity.
*/
- public @DataActivityType int getDataActivity() {
+ @DataActivityType
+ public int getDataActivity() {
return mDataActivity;
}
@@ -1048,7 +1058,7 @@
/* ss should always be non-null */
if (!TextUtils.isEmpty(ss.getOperatorNumeric())) {
plmn = ss.getOperatorNumeric();
- } else if (cellIdentity != null && !TextUtils.isEmpty(cellIdentity.getPlmn())) {
+ } else if (!TextUtils.isEmpty(cellIdentity.getPlmn())) {
plmn = cellIdentity.getPlmn();
} else {
plmn = UNKNOWN_PLMN;
@@ -1059,7 +1069,6 @@
mPlmn = plmn;
}
- boolean updatedRat = false;
NetworkRegistrationInfo nri = getDataNri();
if (nri != null) {
int dataRat = nri.getAccessNetworkTechnology();
@@ -1133,7 +1142,7 @@
}
@Override
public boolean equals(@Nullable Object o) {
- if (o == null || !(o instanceof NetworkKey) || hashCode() != o.hashCode()) {
+ if (!(o instanceof NetworkKey that) || hashCode() != o.hashCode()) {
return false;
}
@@ -1141,7 +1150,6 @@
return true;
}
- NetworkKey that = (NetworkKey) o;
return mPlmn.equals(that.mPlmn)
&& mTac == that.mTac
&& mDataRat.equals(that.mDataRat);
@@ -1153,11 +1161,7 @@
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("Plmn").append(mPlmn)
- .append("Rat").append(mDataRat)
- .append("Tac").append(mTac);
- return sb.toString();
+ return "Plmn" + mPlmn + "Rat" + mDataRat + "Tac" + mTac;
}
}
@@ -1216,11 +1220,7 @@
}
private String getDataKey(int link, int level) {
- StringBuilder sb = new StringBuilder();
- return sb.append(mKey)
- .append("Link").append(link)
- .append("Level").append(level)
- .toString();
+ return mKey + "Link" + link + "Level" + level;
}
/** Get the accumulated bandwidth value */
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index 5c1d0e1..b7aa251 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -32,7 +32,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -46,7 +45,6 @@
import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.AsyncResult;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -68,6 +66,7 @@
import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Log;
+import android.util.SparseIntArray;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
@@ -84,6 +83,7 @@
import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch;
@@ -103,11 +103,12 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
/**
* Utility singleton to monitor subscription changes and incoming NetworkRequests
* and determine which phone/phones are active.
- *
+ * <p>
* Manages the ALLOW_DATA calls to modems and notifies phones about changes to
* the active phones. Note we don't wait for data attach (which may not happen anyway).
*/
@@ -214,7 +215,6 @@
}
};
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
// How many phones (correspondingly logical modems) are allowed for PS attach. This is used
// when we specifically use setDataAllowed to initiate on-demand PS(data) attach for each phone.
protected int mMaxDataAttachModemCount;
@@ -320,7 +320,8 @@
private ConnectivityManager mConnectivityManager;
private int mImsRegistrationTech = REGISTRATION_TECH_NONE;
-
+ @VisibleForTesting
+ public final SparseIntArray mImsRegistrationRadioTechMap = new SparseIntArray();
private List<Set<CommandException.Error>> mCurrentDdsSwitchFailure;
/** Data settings manager callback. Key is the phone id. */
@@ -390,6 +391,27 @@
(context, phoneId) -> ImsManager.getInstance(context, phoneId).getRegistrationTech();
/**
+ * Interface to register RegistrationCallback. It's a wrapper of
+ * ImsManager#addRegistrationCallback, to make it mock-able in unittests.
+ */
+ public interface ImsRegisterCallback {
+ /** Set RegistrationCallback. */
+ void setCallback(Context context, int phoneId, RegistrationManager.RegistrationCallback cb,
+ Executor executor) throws ImsException;
+ }
+
+ @VisibleForTesting
+ public ImsRegisterCallback mImsRegisterCallback =
+ (context, phoneId, cb, executor)-> {
+ try {
+ ImsManager.getInstance(context, phoneId)
+ .addRegistrationCallback(cb, executor);
+ } catch (ImsException e) {
+ throw e;
+ }
+ };
+
+ /**
* Method to get singleton instance.
*/
public static PhoneSwitcher getInstance() {
@@ -432,8 +454,7 @@
private void registerForImsRadioTechChange(Context context, int phoneId) {
try {
- ImsManager.getInstance(context, phoneId).addRegistrationCallback(
- mRegistrationCallback, this::post);
+ mImsRegisterCallback.setCallback(context, phoneId, mRegistrationCallback, this::post);
mIsRegisteredForImsRadioTechChange = true;
} catch (ImsException imsException) {
mIsRegisteredForImsRadioTechChange = false;
@@ -494,6 +515,14 @@
if (phone.getImsPhone() != null) {
phone.getImsPhone().registerForPreciseCallStateChanged(
this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
+ if (mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ // Initialize IMS registration tech
+ mImsRegistrationRadioTechMap.put(phoneId, REGISTRATION_TECH_NONE);
+ ((ImsPhone) phone.getImsPhone()).registerForImsRegistrationChanges(
+ this, EVENT_IMS_RADIO_TECH_CHANGED, null);
+
+ log("register handler to receive IMS registration : " + phoneId);
+ }
}
mDataSettingsManagerCallbacks.computeIfAbsent(phoneId,
v -> new DataSettingsManagerCallback(this::post) {
@@ -511,7 +540,10 @@
}});
phone.getDataSettingsManager().registerCallback(
mDataSettingsManagerCallbacks.get(phoneId));
- registerForImsRadioTechChange(context, phoneId);
+
+ if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ registerForImsRadioTechChange(context, phoneId);
+ }
}
Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>();
mCurrentDdsSwitchFailure.add(ddsFailure);
@@ -721,7 +753,18 @@
case EVENT_IMS_RADIO_TECH_CHANGED: {
// register for radio tech change to listen to radio tech handover in case previous
// attempt was not successful
- registerForImsRadioTechChange();
+ if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ registerForImsRadioTechChange();
+ } else {
+ if (msg.obj == null) {
+ log("EVENT_IMS_RADIO_TECH_CHANGED but parameter is not available");
+ break;
+ }
+ if (!onImsRadioTechChanged((AsyncResult) (msg.obj))) {
+ break;
+ }
+ }
+
// if voice call state changes or in voice call didn't change
// but RAT changes(e.g. Iwlan -> cross sim), reevaluate for data switch.
if (updatesIfPhoneInVoiceCallChanged() || isAnyVoiceCallActiveOnDevice()) {
@@ -733,7 +776,9 @@
case EVENT_PRECISE_CALL_STATE_CHANGED: {
// register for radio tech change to listen to radio tech handover in case previous
// attempt was not successful
- registerForImsRadioTechChange();
+ if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ registerForImsRadioTechChange();
+ }
// If the phoneId in voice call didn't change, do nothing.
if (!updatesIfPhoneInVoiceCallChanged()) {
@@ -885,6 +930,45 @@
}
}
+ /**
+ * Only provide service for the handler of PhoneSwitcher.
+ * @return true if the radio tech changed, otherwise false
+ */
+ private boolean onImsRadioTechChanged(@NonNull AsyncResult asyncResult) {
+ ImsPhone.ImsRegistrationRadioTechInfo imsRegistrationRadioTechInfo =
+ (ImsPhone.ImsRegistrationRadioTechInfo) asyncResult.result;
+ if (imsRegistrationRadioTechInfo == null
+ || imsRegistrationRadioTechInfo.phoneId() == INVALID_PHONE_INDEX
+ || imsRegistrationRadioTechInfo.imsRegistrationState()
+ == RegistrationManager.REGISTRATION_STATE_REGISTERING) {
+ // Ignore REGISTERING state, handle only REGISTERED and NOT_REGISTERED
+ log("onImsRadioTechChanged : result is not available");
+ return false;
+ }
+
+ int phoneId = imsRegistrationRadioTechInfo.phoneId();
+ int subId = SubscriptionManager.getSubscriptionId(phoneId);
+ int tech = imsRegistrationRadioTechInfo.imsRegistrationTech();
+ log("onImsRadioTechChanged phoneId : " + phoneId + " subId : " + subId + " old tech : "
+ + mImsRegistrationRadioTechMap.get(phoneId, REGISTRATION_TECH_NONE)
+ + " new tech : " + tech);
+
+ if (mImsRegistrationRadioTechMap.get(phoneId, REGISTRATION_TECH_NONE) == tech) {
+ // Registration tech not changed
+ return false;
+ }
+
+ mImsRegistrationRadioTechMap.put(phoneId, tech);
+
+ if (subId == INVALID_SUBSCRIPTION_ID) {
+ // Need to update the cached IMS registration tech but no need to do any of the
+ // following. When the SIM removed, REGISTRATION_STATE_NOT_REGISTERED is notified.
+ return false;
+ }
+
+ return true;
+ }
+
private synchronized void onMultiSimConfigChanged(int activeModemCount) {
// No change.
if (mActiveModemCount == activeModemCount) return;
@@ -911,6 +995,14 @@
if (phone.getImsPhone() != null) {
phone.getImsPhone().registerForPreciseCallStateChanged(
this, EVENT_PRECISE_CALL_STATE_CHANGED, null);
+ if (mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ // Initialize IMS registration tech for new phoneId
+ mImsRegistrationRadioTechMap.put(phoneId, REGISTRATION_TECH_NONE);
+ ((ImsPhone) phone.getImsPhone()).registerForImsRegistrationChanges(
+ this, EVENT_IMS_RADIO_TECH_CHANGED, null);
+
+ log("register handler to receive IMS registration : " + phoneId);
+ }
}
mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(),
@@ -933,7 +1025,10 @@
Set<CommandException.Error> ddsFailure = new HashSet<CommandException.Error>();
mCurrentDdsSwitchFailure.add(ddsFailure);
- registerForImsRadioTechChange(mContext, phoneId);
+
+ if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ registerForImsRadioTechChange(mContext, phoneId);
+ }
}
mAutoDataSwitchController.onMultiSimConfigChanged(activeModemCount);
@@ -1100,10 +1195,14 @@
mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID;
}
mPhoneSubscriptions[i] = sub;
- // Listen to IMS radio tech change for new sub
- if (SubscriptionManager.isValidSubscriptionId(sub)) {
- registerForImsRadioTechChange(mContext, i);
+
+ if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ // Listen to IMS radio tech change for new sub
+ if (SubscriptionManager.isValidSubscriptionId(sub)) {
+ registerForImsRadioTechChange(mContext, i);
+ }
}
+
diffDetected = true;
mAutoDataSwitchController.notifySubscriptionsMappingChanged();
}
@@ -1216,12 +1315,10 @@
public long lastRequested = 0;
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected void activate(int phoneId) {
switchPhone(phoneId, true);
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected void deactivate(int phoneId) {
switchPhone(phoneId, false);
}
@@ -1492,10 +1589,6 @@
r.notifyRegistrant();
}
- public void unregisterForActivePhoneSwitch(Handler h) {
- mActivePhoneRegistrants.remove(h);
- }
-
/**
* Set opportunistic data subscription. It's an indication to switch Internet data to this
* subscription. It has to be an active subscription, and PhoneSwitcher will try to validate
@@ -1735,7 +1828,6 @@
* Log debug messages and also log into the local log.
* @param l debug messages
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected void logl(String l) {
log(l);
mLocalLog.log(l);
@@ -1838,12 +1930,6 @@
return mAutoSelectedDataSubId;
}
- // TODO (b/148396668): add an internal callback method to monitor phone capability change,
- // and hook this call to that callback.
- private void onPhoneCapabilityChanged(PhoneCapability capability) {
- onPhoneCapabilityChangedInternal(capability);
- }
-
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
pw.println("PhoneSwitcher:");
diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java
index ac04627..ebddbad 100644
--- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java
+++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java
@@ -53,10 +53,14 @@
private static final int DEDICATED_BEARER_EVENT_STATE_MODIFIED = 2;
private static final int DEDICATED_BEARER_EVENT_STATE_DELETED = 3;
- private final @NonNull String mLogTag;
- private final @NonNull TelephonyNetworkAgent mNetworkAgent;
- private final @NonNull Map<Integer, QosBearerSession> mQosBearerSessions;
- private final @NonNull RcsStats mRcsStats;
+ @NonNull
+ private final String mLogTag;
+ @NonNull
+ private final TelephonyNetworkAgent mNetworkAgent;
+ @NonNull
+ private final Map<Integer, QosBearerSession> mQosBearerSessions;
+ @NonNull
+ private final RcsStats mRcsStats;
// We perform an exact match on the address
private final @NonNull Map<Integer, IFilter> mCallbacksToFilter;
diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java
index 5ed09e6..d90724e 100644
--- a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java
+++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java
@@ -54,10 +54,8 @@
private static final int NETWORK_AGENT_TEARDOWN_DELAY_MS = 5_000;
/** The parent data network. */
- private final @NonNull DataNetwork mDataNetwork;
-
- /** Network agent config. For unit test use only. */
- private final @NonNull NetworkAgentConfig mNetworkAgentConfig;
+ @NonNull
+ private final DataNetwork mDataNetwork;
/** This is the id from {@link NetworkAgent#register()}. */
private final int mId;
@@ -165,7 +163,6 @@
config, provider);
register();
mDataNetwork = dataNetwork;
- mNetworkAgentConfig = config;
mTelephonyNetworkAgentCallbacks.add(callback);
mId = getNetwork().getNetId();
mLogTag = "TNA-" + mId;
@@ -345,15 +342,6 @@
}
/**
- * Log debug messages and also log into the local log.
- * @param s debug messages
- */
- private void logl(@NonNull String s) {
- log(s);
- mLocalLog.log(s);
- }
-
- /**
* Dump the state of TelephonyNetworkAgent
*
* @param fd File descriptor
diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
index 877d7b8..a16cee6 100644
--- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
@@ -72,14 +72,15 @@
private final Phone mPhone;
- private AccessNetworksManager mAccessNetworksManager;
+ private final AccessNetworksManager mAccessNetworksManager;
private int mSubscriptionId;
@VisibleForTesting
public final Handler mInternalHandler;
- private final @NonNull FeatureFlags mFlags;
+ @NonNull
+ private final FeatureFlags mFlags;
/**
@@ -109,20 +110,19 @@
null);
mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener(
- mSubscriptionsChangedListener);
+ SubscriptionManager.OnSubscriptionsChangedListener subscriptionsChangedListener =
+ new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ mInternalHandler.sendEmptyMessage(EVENT_SUBSCRIPTION_CHANGED);
+ }};
+
+ mPhone.getContext().getSystemService(SubscriptionManager.class)
+ .addOnSubscriptionsChangedListener(subscriptionsChangedListener);
register();
}
- private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener =
- new SubscriptionManager.OnSubscriptionsChangedListener() {
- @Override
- public void onSubscriptionsChanged() {
- mInternalHandler.sendEmptyMessage(EVENT_SUBSCRIPTION_CHANGED);
- }
- };
-
private NetworkCapabilities makeNetworkFilterByPhoneId(int phoneId) {
return makeNetworkFilter(SubscriptionManager.getSubscriptionId(phoneId));
}
@@ -291,13 +291,13 @@
}
@Override
- public void releaseNetworkFor(NetworkRequest networkRequest) {
+ public void releaseNetworkFor(@NonNull NetworkRequest networkRequest) {
Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_RELEASE);
msg.obj = networkRequest;
msg.sendToTarget();
}
- private void onReleaseNetworkFor(Message msg) {
+ private void onReleaseNetworkFor(@NonNull Message msg) {
TelephonyNetworkRequest networkRequest =
new TelephonyNetworkRequest((NetworkRequest) msg.obj, mPhone, mFlags);
boolean applied = mNetworkRequests.get(networkRequest)
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
index 6e1c8dd..e511e8f 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
@@ -31,8 +31,10 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.service.euicc.EuiccProfileInfo;
@@ -75,6 +77,7 @@
private UiccController mUiccController;
private FeatureFlags mFeatureFlags;
private PackageManager mPackageManager;
+ private final int mVendorApiLevel;
private static EuiccCardController sInstance;
@@ -143,6 +146,8 @@
mEuiccController = euiccController;
mFeatureFlags = featureFlags;
mPackageManager = context.getPackageManager();
+ mVendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
if (isBootUp(mContext)) {
mSimSlotStatusChangeReceiver = new SimSlotStatusChangedBroadcastReceiver();
@@ -1541,7 +1546,11 @@
if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
|| !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
- Binder.getCallingUserHandle())) {
+ Binder.getCallingUserHandle())
+ || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ // Skip to check associated telephony feature,
+ // if compatibility change is not enabled for the current process or
+ // the SDK version of vendor partition is less than Android V.
return;
}
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 18b4b14..1a5b99e 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -34,7 +34,9 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -124,6 +126,7 @@
private final AppOpsManager mAppOpsManager;
private final PackageManager mPackageManager;
private final FeatureFlags mFeatureFlags;
+ private final int mVendorApiLevel;
// These values should be set or updated upon 1) system boot, 2) EuiccService/LPA is bound to
// the phone process, 3) values are updated remotely by server flags.
@@ -172,6 +175,8 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mPackageManager = context.getPackageManager();
mFeatureFlags = featureFlags;
+ mVendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
}
/**
@@ -615,25 +620,32 @@
void downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription,
boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
Bundle resolvedBundle, PendingIntent callbackIntent) {
- boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
- boolean callerCanDownloadAdminManagedSubscription =
- Flags.esimManagementEnabled()
- && callerCanManageDevicePolicyManagedSubscriptions(callingPackage);
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
+
+ boolean callerHasAdminPrivileges = false;
if (Flags.esimManagementEnabled()) {
- if (mContext
- .getSystemService(UserManager.class)
- .hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY)
- && !callerCanDownloadAdminManagedSubscription) {
+ callerHasAdminPrivileges = callerCanManageDevicePolicyManagedSubscriptions(
+ callingPackage);
+ if (callerHasAdminPrivileges && (switchAfterDownload && !shouldAllowSwitchAfterDownload(
+ callingPackage))) {
+ // Throw error if calling admin does not have privileges to enable
+ // subscription silently after download but switchAfterDownload is passed as true.
+ sendResult(callbackIntent, ERROR, null);
+ return;
+ }
+ if (mContext.getSystemService(UserManager.class).hasUserRestriction(
+ UserManager.DISALLOW_SIM_GLOBALLY) && !callerHasAdminPrivileges) {
// Only admin managed subscriptions are allowed, but the caller is not authorised to
// download admin managed subscriptions. Abort.
- throw new SecurityException("Caller is not authorized to download subscriptions");
+ sendResult(callbackIntent, ERROR, null);
+ return;
}
}
- mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
// Don't try to resolve the port index for apps which are not targeting on T for backward
// compatibility. instead always use default port 0.
boolean shouldResolvePortIndex = isCompatChangeEnabled(callingPackage,
EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS);
+ boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
long token = Binder.clearCallingIdentity();
try {
@@ -646,26 +658,19 @@
isConsentNeededToResolvePortIndex = (portIndex
== TelephonyManager.INVALID_PORT_INDEX);
}
- // Caller has admin privileges if they can download admin managed subscription,
- // and are not switching the subscription after download (admins cannot silently
- // enable the subscription).
- boolean hasAdminPrivileges =
- callerCanDownloadAdminManagedSubscription && !switchAfterDownload;
Log.d(TAG, " downloadSubscription cardId: " + cardId + " switchAfterDownload: "
- + switchAfterDownload + " portIndex: " + portIndex
- + " forceDeactivateSim: " + forceDeactivateSim + " callingPackage: "
- + callingPackage
+ + switchAfterDownload + " portIndex: " + portIndex + " forceDeactivateSim: "
+ + forceDeactivateSim + " callingPackage: " + callingPackage
+ " isConsentNeededToResolvePortIndex: " + isConsentNeededToResolvePortIndex
+ " shouldResolvePortIndex:" + shouldResolvePortIndex
- + " hasAdminPrivileges:" + hasAdminPrivileges);
- if (!isConsentNeededToResolvePortIndex
- && (callerCanWriteEmbeddedSubscriptions
- || hasAdminPrivileges)) {
+ + " callerHasAdminPrivileges:" + callerHasAdminPrivileges);
+ if (!isConsentNeededToResolvePortIndex && (callerCanWriteEmbeddedSubscriptions
+ || callerHasAdminPrivileges)) {
// With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
// and move straight to the profile download.
downloadSubscriptionPrivileged(cardId, portIndex, token, subscription,
switchAfterDownload, forceDeactivateSim, callingPackage, resolvedBundle,
- callbackIntent, callerCanDownloadAdminManagedSubscription,
+ callbackIntent, callerHasAdminPrivileges,
getCurrentEmbeddedSubscriptionIds(cardId));
return;
}
@@ -862,8 +867,11 @@
cardId,
existingSubscriptions);
return;
+ } else if (markAsOwnedByAdmin) {
+ refreshSubscriptionsOwnership(true, callingPackage, cardId,
+ existingSubscriptions);
}
- break;
+ break;
case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
resultCode = RESOLVABLE_ERROR;
addResolutionIntentWithPort(extrasIntent,
@@ -1728,22 +1736,27 @@
SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions(
List.of(mTelephonyManager.getCardIdForDefaultEuicc()),
() -> {
- if (Flags.esimManagementEnabled() && isCallerAdmin) {
- // Mark the newly downloaded subscriptions as being owned by an admin so
- // that actions for that subscription can be restricted,
- // and the admin is limited to effecting only these subscriptions.
- Set<Integer> subscriptionsAfter = getCurrentEmbeddedSubscriptionIds(cardId);
- subscriptionsAfter.removeAll(subscriptionsBefore);
- for (int subId: subscriptionsAfter) {
- SubscriptionManagerService
- .getInstance().setGroupOwner(subId, callingPackage);
- }
- }
+ refreshSubscriptionsOwnership(isCallerAdmin, callingPackage, cardId,
+ subscriptionsBefore);
sendResult(callbackIntent, resultCode, extrasIntent);
});
}
+ private void refreshSubscriptionsOwnership(boolean isCallerAdmin, String callingPackage,
+ int cardId, Set<Integer> subscriptionsBefore) {
+ if (Flags.esimManagementEnabled() && isCallerAdmin) {
+ // Mark the newly downloaded subscriptions as being owned by an admin so
+ // that actions for that subscription can be restricted,
+ // and the admin is limited to effecting only these subscriptions.
+ Set<Integer> subscriptionsAfter = getCurrentEmbeddedSubscriptionIds(cardId);
+ subscriptionsAfter.removeAll(subscriptionsBefore);
+ for (int subId : subscriptionsAfter) {
+ SubscriptionManagerService.getInstance().setGroupOwner(subId, callingPackage);
+ }
+ }
+ }
+
/** Dispatch the given callback intent with the given result code and data. */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
@@ -2181,20 +2194,31 @@
}
private boolean callerCanManageDevicePolicyManagedSubscriptions(String callingPackage) {
- // isProfileOwner/isDeviceOwner needs to callers user, so create device policy manager
- // with the correct context associated with the caller.
+ DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
+ boolean isAdmin =
+ devicePolicyManager != null && (devicePolicyManager.isProfileOwnerApp(
+ callingPackage)
+ || devicePolicyManager.isDeviceOwnerApp(callingPackage));
+ return isAdmin || mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean shouldAllowSwitchAfterDownload(String callingPackage) {
+ DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
+ return devicePolicyManager != null && (devicePolicyManager.isDeviceOwnerApp(callingPackage)
+ || (devicePolicyManager.isProfileOwnerApp(callingPackage)
+ && devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()));
+ }
+
+ private DevicePolicyManager getDevicePolicyManager() {
+ // create device policy manager with the correct context associated with the caller.
DevicePolicyManager devicePolicyManager =
retrieveDevicePolicyManagerFromUserContext(Binder.getCallingUserHandle());
if (devicePolicyManager == null) {
Log.w(TAG, "Unable to get device policy manager");
- return false;
}
- boolean isAdmin =
- devicePolicyManager.isProfileOwnerApp(callingPackage)
- || devicePolicyManager.isDeviceOwnerApp(callingPackage);
- return isAdmin || mContext.checkCallingOrSelfPermission(
- Manifest.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS)
- == PackageManager.PERMISSION_GRANTED;
+ return devicePolicyManager;
}
@Override
@@ -2351,7 +2375,11 @@
if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
|| !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
- Binder.getCallingUserHandle())) {
+ Binder.getCallingUserHandle())
+ || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ // Skip to check associated telephony feature,
+ // if compatibility change is not enabled for the current process or
+ // the SDK version of vendor partition is less than Android V.
return;
}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 9de3ee9..c003405 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -200,6 +200,12 @@
10 = dialing number
*/
+ /**
+ * An FAC code is of the following format:
+ * #FAC#MSISDN*
+ */
+ static Pattern sFac = Pattern.compile("^\\#\\d+\\#[^*]+\\*$");
+
static final int MATCH_GROUP_POUND_STRING = 1;
static final int MATCH_GROUP_ACTION = 2;
@@ -274,7 +280,9 @@
// in India operator(Mumbai MTNL)
ret = new GsmMmiCode(phone, app);
ret.mPoundString = dialString;
- } else if (ret.isFacToDial()) {
+ } else if (ret.isFacToDial(dialString)) {
+ // Note: we had to pass in the dial string above because the full dial string is not
+ // in the MmiCode class (or even needed there).
// This is a FAC (feature access code) to dial as a normal call.
ret = null;
}
@@ -963,12 +971,28 @@
}
/**
+ * Determines if a full dial string matches the general format of a FAC code.
+ * Ie. #FAC#MSIDN*
+ * @param dialString The full dialed number.
+ * @return {@code true} if the dialed number has the general format of a FAC code.
+ */
+ private static boolean isFacFormatNumber(String dialString) {
+ Matcher m = sFac.matcher(dialString);
+ return m.matches();
+ }
+
+ /**
* Returns true if the Service Code is FAC to dial as a normal call.
*
* FAC stands for feature access code and it is special patterns of characters
* to invoke certain features.
*/
- private boolean isFacToDial() {
+ private boolean isFacToDial(String dialString) {
+ if (!isFacFormatNumber(dialString)) {
+ // If the full dial string doesn't conform to the required format for a FAC, we will
+ // bail early. It is likely a true USSD which shares the same code as the FAC.
+ return false;
+ }
CarrierConfigManager configManager = (CarrierConfigManager)
mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java
index 49b7e62..eb389b7 100644
--- a/src/java/com/android/internal/telephony/ims/ImsResolver.java
+++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java
@@ -60,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -139,11 +140,12 @@
* Create the ImsResolver Service singleton instance.
*/
public static void make(Context context, String defaultMmTelPackageName,
- String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) {
+ String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo,
+ FeatureFlags featureFlags) {
if (sInstance == null) {
sHandlerThread.start();
sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName,
- numSlots, repo, sHandlerThread.getLooper());
+ numSlots, repo, sHandlerThread.getLooper(), featureFlags);
}
}
@@ -372,7 +374,7 @@
*/
ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository repo);
+ ImsFeatureBinderRepository repo, FeatureFlags featureFlags);
}
private ImsServiceControllerFactory mImsServiceControllerFactory =
@@ -386,8 +388,9 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository repo) {
- return new ImsServiceController(context, componentName, callbacks, repo);
+ ImsFeatureBinderRepository repo, FeatureFlags featureFlags) {
+ return new ImsServiceController(context, componentName, callbacks, repo,
+ featureFlags);
}
};
@@ -410,7 +413,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository repo) {
+ ImsFeatureBinderRepository repo, FeatureFlags featureFlags) {
return new ImsServiceControllerCompat(context, componentName, callbacks, repo);
}
};
@@ -445,6 +448,9 @@
// Synchronize all events on a handler to ensure that the cache includes the most recent
// version of the installed ImsServices.
private final Handler mHandler;
+
+ private final FeatureFlags mFeatureFlags;
+
private class ResolverHandler extends Handler {
ResolverHandler(Looper looper) {
@@ -581,7 +587,7 @@
public ImsResolver(Context context, String defaultMmTelPackageName,
String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo,
- Looper looper) {
+ Looper looper, FeatureFlags featureFlags) {
Log.i(TAG, "device MMTEL package: " + defaultMmTelPackageName + ", device RCS package:"
+ defaultRcsPackageName);
mContext = context;
@@ -591,6 +597,7 @@
mHandler = new ResolverHandler(looper);
mRunnableExecutor = new HandlerExecutor(mHandler);
+ mFeatureFlags = featureFlags;
mCarrierServices = new SparseArray<>(mNumSlots);
setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_EMERGENCY_MMTEL);
setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_MMTEL);
@@ -1233,7 +1240,8 @@
Log.w(TAG, "bindImsService: error=" + e.getMessage());
}
} else {
- controller = info.controllerFactory.create(mContext, info.name, this, mRepo);
+ controller = info.controllerFactory.create(mContext, info.name, this, mRepo,
+ mFeatureFlags);
Log.i(TAG, "Binding ImsService: " + controller.getComponentName()
+ " with features: " + features);
controller.bind(features, slotIdToSubIdMap);
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index 6af7a08..ea8399f 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -49,6 +49,7 @@
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ExponentialBackoff;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.util.TelephonyUtils;
import java.io.PrintWriter;
@@ -265,6 +266,7 @@
private final HandlerThread mHandlerThread = new HandlerThread("ImsServiceControllerHandler");
private final Handler mHandler;
private final LegacyPermissionManager mPermissionManager;
+ private final FeatureFlags mFeatureFlags;
private ImsFeatureBinderRepository mRepo;
private ImsServiceControllerCallbacks mCallbacks;
private ExponentialBackoff mBackoff;
@@ -353,7 +355,8 @@
};
public ImsServiceController(Context context, ComponentName componentName,
- ImsServiceControllerCallbacks callbacks, ImsFeatureBinderRepository repo) {
+ ImsServiceControllerCallbacks callbacks, ImsFeatureBinderRepository repo,
+ FeatureFlags featureFlags) {
mContext = context;
mComponentName = componentName;
mCallbacks = callbacks;
@@ -369,6 +372,7 @@
Context.LEGACY_PERMISSION_SERVICE);
mRepo = repo;
mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper(), componentName);
+ mFeatureFlags = featureFlags;
mPackageManager = mContext.getPackageManager();
if (mPackageManager != null) {
mChangedPackages = mPackageManager.getChangedPackages(mLastSequenceNumber);
@@ -383,7 +387,7 @@
// testing, use a handler supplied by the testing system.
public ImsServiceController(Context context, ComponentName componentName,
ImsServiceControllerCallbacks callbacks, Handler handler, RebindRetry rebindRetry,
- ImsFeatureBinderRepository repo) {
+ ImsFeatureBinderRepository repo, FeatureFlags featureFlags) {
mContext = context;
mComponentName = componentName;
mCallbacks = callbacks;
@@ -396,6 +400,7 @@
mRestartImsServiceRunnable);
mPermissionManager = null;
mRepo = repo;
+ mFeatureFlags = featureFlags;
mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper(), componentName);
}
@@ -493,6 +498,12 @@
synchronized (mLock) {
HashSet<Integer> slotIDs = newImsFeatures.stream().map(e -> e.slotId).collect(
Collectors.toCollection(HashSet::new));
+
+ // Set the number of slot for IMS enable for each slot
+ if (mFeatureFlags.setNumberOfSimForImsEnable()) {
+ mImsEnablementTracker.setNumOfSlots(slotIDs.size());
+ }
+
// detect which subIds have changed on a per-slot basis
SparseIntArray changedSubIds = new SparseIntArray(slotIDs.size());
for (Integer slotID : slotIDs) {
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java b/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
index 778bd0e..440d784 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java
@@ -38,6 +38,7 @@
import com.android.ims.internal.IImsMMTelFeature;
import com.android.ims.internal.IImsServiceController;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlagsImpl;
/**
* Manages the Binding lifecycle of one ImsService as well as the relevant ImsFeatures that the
@@ -76,7 +77,7 @@
public ImsServiceControllerCompat(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
ImsFeatureBinderRepository repo) {
- super(context, componentName, callbacks, repo);
+ super(context, componentName, callbacks, repo, new FeatureFlagsImpl());
mMmTelFeatureFactory = MmTelFeatureCompatAdapter::new;
}
@@ -84,7 +85,8 @@
public ImsServiceControllerCompat(Context context, ComponentName componentName,
ImsServiceControllerCallbacks callbacks, Handler handler, RebindRetry rebindRetry,
ImsFeatureBinderRepository repo, MmTelFeatureCompatFactory factory) {
- super(context, componentName, callbacks, handler, rebindRetry, repo);
+ super(context, componentName, callbacks, handler, rebindRetry, repo,
+ new FeatureFlagsImpl());
mMmTelFeatureFactory = factory;
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index a6bb1d6..10cbe77 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -21,6 +21,7 @@
import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE;
import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGISTERED;
+import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGISTERING;
import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE;
import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS;
import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK;
@@ -75,6 +76,7 @@
import android.os.UserHandle;
import android.preference.PreferenceManager;
import android.sysprop.TelephonyProperties;
+import android.telecom.VideoProfile;
import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.NetworkRegistrationInfo;
@@ -263,6 +265,14 @@
}
}
+ /**
+ * Container to transfer IMS registration radio tech.
+ * This will be used as result value of AsyncResult to the handler that called
+ * {@link #registerForImsRegistrationChanges(Handler, int, Object)}
+ */
+ public record ImsRegistrationRadioTechInfo(int phoneId, int imsRegistrationTech,
+ int imsRegistrationState) {}
+
// Instance Variables
Phone mDefaultPhone;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -802,7 +812,11 @@
try {
if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) {
if (DBG) logd("MmiCode 2: accept ringing call");
- mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
+ if (mFeatureFlags.answerAudioOnlyWhenAnsweringViaMmiCode()) {
+ mCT.acceptCall(VideoProfile.STATE_AUDIO_ONLY);
+ } else {
+ mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
+ }
} else if (getBackgroundCall().getState() == ImsPhoneCall.State.HOLDING) {
// If there's an active ongoing call as well, hold it and the background one
// should automatically unhold. Otherwise just unhold the background call.
@@ -2504,7 +2518,15 @@
updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED,
attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE,
imsTransportType);
- AsyncResult ar = new AsyncResult(null, null, null);
+
+ AsyncResult ar;
+ if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId,
+ attributes.getRegistrationTechnology(), REGISTRATION_STATE_REGISTERED),
+ null);
+ } else {
+ ar = new AsyncResult(null, null, null);
+ }
mImsRegistrationUpdateRegistrants.notifyRegistrants(ar);
}
@@ -2521,7 +2543,15 @@
mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.PROGRESSING,
null);
mImsStats.onImsRegistering(imsRadioTech);
- AsyncResult ar = new AsyncResult(null, null, null);
+
+ AsyncResult ar;
+ if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId,
+ imsRadioTech, REGISTRATION_STATE_REGISTERING),
+ null);
+ } else {
+ ar = new AsyncResult(null, null, null);
+ }
mImsRegistrationUpdateRegistrants.notifyRegistrants(ar);
}
@@ -2564,7 +2594,15 @@
setCurrentSubscriberUris(null);
clearPhoneNumberForSourceIms();
}
- AsyncResult ar = new AsyncResult(null, null, null);
+
+ AsyncResult ar;
+ if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) {
+ ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId,
+ REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED),
+ null);
+ } else {
+ ar = new AsyncResult(null, null, null);
+ }
mImsRegistrationUpdateRegistrants.notifyRegistrants(ar);
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index a71355d..aee8867 100755
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -157,6 +157,11 @@
*/
private boolean mIsHeldByRemote = false;
+ /**
+ * Used to indicate if both the user and carrier config have enabled the business composer.
+ */
+ private boolean mIsBusinessComposerFeatureEnabled = false;
+
//***** Event Constants
private static final int EVENT_DTMF_DONE = 1;
private static final int EVENT_PAUSE_DONE = 2;
@@ -230,6 +235,10 @@
mCreateTime = System.currentTimeMillis();
mUusInfo = null;
+ if (com.android.server.telecom.flags.Flags.businessCallComposer()) {
+ setIsBusinessComposerFeatureEnabled(phone);
+ }
+
// Ensure any extras set on the ImsCallProfile at the start of the call are cached locally
// in the ImsPhoneConnection. This isn't going to inform any listeners (since the original
// connection is not likely to be associated with a TelephonyConnection yet).
@@ -1389,10 +1398,18 @@
* ImsCallProfile.EXTRA_ASSERTED_DISPLAY_NAME). This helper notifies Telecom of the business
* composer values which will then be injected into the android.telecom.Call object.
*/
- private void maybeInjectBusinessComposerExtras(Bundle extras) {
+ @VisibleForTesting
+ public void maybeInjectBusinessComposerExtras(Bundle extras) {
if (extras == null) {
return;
}
+ // Telephony should check that the business composer features is on BEFORE
+ // propagating the business call extras. This prevents the user from getting
+ // business call info when they turned the feature off.
+ if (!mIsBusinessComposerFeatureEnabled) {
+ Rlog.i(LOG_TAG, "mIBCE: business composer feature is NOT enabled");
+ return;
+ }
try {
if (extras.containsKey(ImsCallProfile.EXTRA_IS_BUSINESS_CALL)
&& !extras.containsKey(android.telecom.Call.EXTRA_IS_BUSINESS_CALL)) {
@@ -1413,6 +1430,60 @@
}
}
+ @VisibleForTesting
+ public boolean getIsBusinessComposerFeatureEnabled() {
+ return mIsBusinessComposerFeatureEnabled;
+ }
+
+ @VisibleForTesting
+ public void setIsBusinessComposerFeatureEnabled(Phone phone) {
+ mIsBusinessComposerFeatureEnabled = isBusinessComposerEnabledByConfig(phone)
+ && isBusinessOnlyCallComposerEnabledByUser(phone);
+ Rlog.i(LOG_TAG, String.format(
+ "setIsBusinessComposerFeatureEnabled: mIsBusinessComposerFeatureEnabled=[%b], "
+ + "phone=[%s]", mIsBusinessComposerFeatureEnabled, phone));
+ }
+
+ /**
+ * Returns whether the carrier supports and has enabled the business composer
+ */
+ @VisibleForTesting
+ public boolean isBusinessComposerEnabledByConfig(Phone phone) {
+ PersistableBundle b = null;
+ CarrierConfigManager configMgr = phone.getContext().getSystemService(
+ CarrierConfigManager.class);
+
+ if (configMgr != null) {
+ // If an invalid subId is used, this bundle will contain default values.
+ b = configMgr.getConfigForSubId(phone.getSubId());
+ }
+ if (b != null) {
+ return b.getBoolean(CarrierConfigManager.KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL);
+ } else {
+ // Return static default defined in CarrierConfigManager.
+ return CarrierConfigManager.getDefaultConfig()
+ .getBoolean(CarrierConfigManager.KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL);
+ }
+ }
+
+ /**
+ * Returns whether the user has enabled the business composer
+ */
+ @VisibleForTesting
+ public boolean isBusinessOnlyCallComposerEnabledByUser(Phone phone) {
+ if (phone == null || phone.getContext() == null) {
+ return false;
+ }
+ TelephonyManager tm = (TelephonyManager)
+ phone.getContext().getSystemService(Context.TELEPHONY_SERVICE);
+ if (tm == null) {
+ Rlog.e(LOG_TAG, "isBusinessOnlyCallComposerEnabledByUser: TelephonyManager is null");
+ return false;
+ }
+ return tm.getCallComposerStatus() == TelephonyManager.CALL_COMPOSER_STATUS_BUSINESS_ONLY
+ || tm.getCallComposerStatus() == TelephonyManager.CALL_COMPOSER_STATUS_ON;
+ }
+
private static boolean areBundlesEqual(Bundle extras, Bundle newExtras) {
if (extras == null || newExtras == null) {
return extras == newExtras;
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index 2eadf17..13fb826 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -79,8 +79,9 @@
}
/** Creates a new ongoing atom when data call is set up. */
- public synchronized void onSetupDataCall(@ApnType int apnTypeBitMask) {
- mDataCallSession = getDefaultProto(apnTypeBitMask);
+ public synchronized void onSetupDataCall(@ApnType int apnTypeBitMask,
+ boolean isSatellite) {
+ mDataCallSession = getDefaultProto(apnTypeBitMask, isSatellite);
mStartTime = getTimeMillis();
PhoneFactory.getMetricsCollector().registerOngoingDataCallStat(this);
}
@@ -307,11 +308,13 @@
copy.isNonDds = call.isNonDds;
copy.isIwlanCrossSim = call.isIwlanCrossSim;
copy.isNtn = call.isNtn;
+ copy.isSatelliteTransport = call.isSatelliteTransport;
return copy;
}
/** Creates a proto for a normal {@code DataCallSession} with default values. */
- private DataCallSession getDefaultProto(@ApnType int apnTypeBitmask) {
+ private DataCallSession getDefaultProto(@ApnType int apnTypeBitmask,
+ boolean isSatellite) {
DataCallSession proto = new DataCallSession();
proto.dimension = RANDOM.nextInt();
proto.isMultiSim = SimSlotState.isMultiSim();
@@ -335,6 +338,7 @@
proto.isIwlanCrossSim = false;
proto.isNtn = mSatelliteController != null
? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
+ proto.isSatelliteTransport = isSatellite;
return proto;
}
diff --git a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
index c7ef625..079ff03 100644
--- a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
+++ b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
@@ -16,9 +16,12 @@
package com.android.internal.telephony.metrics;
+import static com.android.internal.telephony.flags.Flags.dataRatMetricEnabled;
+
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseDataConnectionState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
@@ -27,6 +30,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyStatsLog;
import java.util.HashMap;
import java.util.List;
@@ -47,7 +51,10 @@
private int mSubId;
private HashMap<Integer, PreciseDataConnectionState> mLastPreciseDataConnectionState =
new HashMap<>();
- private PreciseDataConnectionStateListenerImpl mDataConnectionStateListener;
+ private TelephonyListenerImpl mTelephonyListener;
+ private int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private int mChannelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_UNSPECIFIED;
private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener =
new SubscriptionManager.OnSubscriptionsChangedListener() {
@@ -132,15 +139,15 @@
TelephonyManager telephonyManager =
mPhone.getContext().getSystemService(TelephonyManager.class);
if (telephonyManager != null) {
- mDataConnectionStateListener = new PreciseDataConnectionStateListenerImpl(mExecutor);
- mDataConnectionStateListener.register(telephonyManager.createForSubscriptionId(subId));
+ mTelephonyListener = new TelephonyListenerImpl(mExecutor);
+ mTelephonyListener.register(telephonyManager.createForSubscriptionId(subId));
}
}
private void unregisterTelephonyListener() {
- if (mDataConnectionStateListener != null) {
- mDataConnectionStateListener.unregister();
- mDataConnectionStateListener = null;
+ if (mTelephonyListener != null) {
+ mTelephonyListener.unregister();
+ mTelephonyListener = null;
}
}
@@ -156,12 +163,46 @@
mPhone.getVoiceCallSessionStats().onPreciseDataConnectionStateChanged(connectionState);
}
- private class PreciseDataConnectionStateListenerImpl extends TelephonyCallback
- implements TelephonyCallback.PreciseDataConnectionStateListener {
+ static int getActiveDataSubId() {
+ if (sDataConnectionStateTracker.size() == 0) {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ return sDataConnectionStateTracker.valueAt(0).mActiveDataSubId;
+ }
+
+ /**
+ * Log RAT if the active data subId changes to another subId with a different RAT.
+ *
+ * @param subId the current active data subId
+ */
+ private void logRATChanges(int subId) {
+ if (mSubId == subId && mActiveDataSubId != subId) {
+ int newDataRat = mPhone.getServiceStateTracker()
+ .getServiceStateStats().getCurrentDataRat();
+ for (int i = 0; i < sDataConnectionStateTracker.size(); i++) {
+ DataConnectionStateTracker dataConnectionStateTracker =
+ sDataConnectionStateTracker.valueAt(0);
+ if (dataConnectionStateTracker.mSubId == mActiveDataSubId) {
+ int previousDataRat = dataConnectionStateTracker.mPhone
+ .getServiceStateTracker().getServiceStateStats()
+ .getCurrentDataRat();
+ if (newDataRat != previousDataRat) {
+ TelephonyStatsLog.write(TelephonyStatsLog.DATA_RAT_STATE_CHANGED,
+ newDataRat);
+ }
+ }
+ }
+ }
+ }
+
+ private class TelephonyListenerImpl extends TelephonyCallback
+ implements TelephonyCallback.PreciseDataConnectionStateListener,
+ TelephonyCallback.ActiveDataSubscriptionIdListener,
+ TelephonyCallback.PhysicalChannelConfigListener {
private final Executor mExecutor;
private TelephonyManager mTelephonyManager = null;
- PreciseDataConnectionStateListenerImpl(Executor executor) {
+ TelephonyListenerImpl(Executor executor) {
mExecutor = executor;
}
@@ -185,5 +226,58 @@
PreciseDataConnectionState connectionState) {
notifyDataConnectionStateChanged(connectionState);
}
+
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ if (dataRatMetricEnabled()) {
+ logRATChanges(subId);
+ }
+ mActiveDataSubId = subId;
+ }
+
+ @Override
+ public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
+ logChannelChange(configs);
+ }
+
+ /** Log channel number if it changes for active data subscription*/
+ private void logChannelChange(List<PhysicalChannelConfig> configs) {
+ int connectedChannelCount = configs.size();
+ int channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_UNSPECIFIED;
+ switch(connectedChannelCount) {
+ case 0:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_ONE;
+ break;
+ case 1:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_ONE;
+ break;
+ case 2:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_TWO;
+ break;
+ case 3:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_THREE;
+ break;
+ case 4:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_FOUR;
+ break;
+ // Greater than 4
+ default:
+ channelCountEnum = TelephonyStatsLog
+ .CONNECTED_CHANNEL_CHANGED__CONNECTED_CHANNEL_COUNT__CHANNEL_COUNT_FIVE;
+ }
+ if (mChannelCountEnum != channelCountEnum) {
+ if (mSubId != mActiveDataSubId) {
+ TelephonyStatsLog.write(TelephonyStatsLog.CONNECTED_CHANNEL_CHANGED,
+ channelCountEnum);
+ }
+ mChannelCountEnum = channelCountEnum;
+ }
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java b/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java
new file mode 100644
index 0000000..fdac834
--- /dev/null
+++ b/src/java/com/android/internal/telephony/metrics/DataNetworkValidationStats.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.metrics;
+
+import android.annotation.ElapsedRealtimeLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.PreciseDataConnectionState;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.TelephonyStatsLog;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
+
+/**
+ * DataNetworkValidationStats logs the atoms for response after a validation request from the
+ * DataNetwork in framework.
+ */
+public class DataNetworkValidationStats {
+
+ private static final String TAG = DataNetworkValidationStats.class.getSimpleName();
+
+ @NonNull
+ private final Phone mPhone;
+
+ @NonNull
+ private final PersistAtomsStorage mAtomsStorage =
+ PhoneFactory.getMetricsCollector().getAtomsStorage();
+
+ @Nullable
+ private DataNetworkValidation mDataNetworkValidation;
+
+ @ElapsedRealtimeLong
+ private long mRequestedTimeInMillis;
+
+ /** constructor */
+ public DataNetworkValidationStats(@NonNull Phone phone) {
+ mPhone = phone;
+ }
+
+
+ /**
+ * Create a new ongoing atom when NetworkValidation requested.
+ *
+ * Create a data network validation proto for a new atom record and write the start time to
+ * calculate the elapsed time required.
+ *
+ * @param apnTypeBitMask APN type bitmask of DataNetwork.
+ */
+ public void onRequestNetworkValidation(@ApnType int apnTypeBitMask) {
+ if (mDataNetworkValidation == null) {
+ mDataNetworkValidation = getDefaultProto(apnTypeBitMask);
+ mRequestedTimeInMillis = getTimeMillis();
+ }
+ }
+
+ /** Mark the Handover Attempt field as true if validation was requested */
+ public void onHandoverAttempted() {
+ if (mDataNetworkValidation != null) {
+ mDataNetworkValidation.handoverAttempted = true;
+ }
+ }
+
+ /**
+ * Called when data network is disconnected.
+ *
+ * Since network validation is based on the data network, validation must also end when the data
+ * network is disconnected. At this time, validation has not been completed, save an atom as
+ * unspecified. and clear.
+ *
+ * @param networkType Current Network Type of the Data Network.
+ */
+ public void onDataNetworkDisconnected(@NetworkType int networkType) {
+ // Nothing to do, if never requested validation
+ if (mDataNetworkValidation == null) {
+ return;
+ }
+
+ // Set data for and atom.
+ calcElapsedTime();
+ mDataNetworkValidation.networkType = networkType;
+ mDataNetworkValidation.signalStrength = mPhone.getSignalStrength().getLevel();
+ mDataNetworkValidation.validationResult = TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED;
+
+ // Store.
+ mAtomsStorage.addDataNetworkValidation(mDataNetworkValidation);
+
+ // clear all values.
+ clear();
+ }
+
+ /**
+ * Store an atom by updated state.
+ *
+ * Called when the validation status is updated, and saves the atom when a failure or success
+ * result is received.
+ *
+ * @param status Data Network Validation Status.
+ * @param networkType Current Network Type of the Data Network.
+ */
+ public void onUpdateNetworkValidationState(
+ @PreciseDataConnectionState.NetworkValidationStatus int status,
+ @NetworkType int networkType) {
+ // Nothing to do, if never requested validation
+ if (mDataNetworkValidation == null) {
+ return;
+ }
+
+ switch (status) {
+ // Immediately after requesting validation, these messages may occur. In this case,
+ // ignore it and wait for the next update.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED: // fall-through
+ case PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS:
+ return;
+ // If status is unsupported, NetworkValidation should not be requested initially. logs
+ // this for abnormal tracking.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED:
+ mDataNetworkValidation.validationResult = TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_NOT_SUPPORTED;
+ break;
+ // Success or failure corresponds to the result, store an atom.
+ case PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS:
+ case PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE:
+ mDataNetworkValidation.validationResult = status;
+ break;
+ }
+
+ // Set data for and atom.
+ calcElapsedTime();
+ mDataNetworkValidation.networkType = networkType;
+ mDataNetworkValidation.signalStrength = mPhone.getSignalStrength().getLevel();
+
+ // Store.
+ mAtomsStorage.addDataNetworkValidation(mDataNetworkValidation);
+
+ // clear all values.
+ clear();
+ }
+
+ /**
+ * Calculate the current time required based on when network validation is requested.
+ */
+ private void calcElapsedTime() {
+ if (mDataNetworkValidation != null && mRequestedTimeInMillis != 0) {
+ mDataNetworkValidation.elapsedTimeInMillis = getTimeMillis() - mRequestedTimeInMillis;
+ }
+ }
+
+ /**
+ * Returns current time in millis from boot.
+ */
+ @VisibleForTesting
+ @ElapsedRealtimeLong
+ protected long getTimeMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Clear all values.
+ */
+ private void clear() {
+ mDataNetworkValidation = null;
+ mRequestedTimeInMillis = 0;
+ }
+
+
+ /** Creates a DataNetworkValidation proto with default values. */
+ @NonNull
+ private DataNetworkValidation getDefaultProto(@ApnType int apnTypeBitmask) {
+ DataNetworkValidation proto = new DataNetworkValidation();
+ proto.networkType =
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_UNKNOWN;
+ proto.apnTypeBitmask = apnTypeBitmask;
+ proto.signalStrength =
+ TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ proto.validationResult =
+ TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED;
+ proto.elapsedTimeInMillis = 0;
+ proto.handoverAttempted = false;
+ proto.networkValidationCount = 1;
+ return proto;
+ }
+}
+
diff --git a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
index 29729c8..9ab52fb 100644
--- a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
+++ b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
@@ -41,7 +41,7 @@
.registerCallback(
new HandlerExecutor(new Handler(mHandlerThread.getLooper())),
state -> {
- updateFoldState(state);
+ updateFoldState(state.getIdentifier());
});
}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 61325316..f07cf60 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -17,9 +17,12 @@
package com.android.internal.telephony.metrics;
import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_TABLE_VERSION;
+import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS;
+import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ROAMING_SATELLITE_SESSION;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SERVICE_SWITCH;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION;
+import static com.android.internal.telephony.TelephonyStatsLog.DATA_NETWORK_VALIDATION;
import static com.android.internal.telephony.TelephonyStatsLog.DEVICE_TELEPHONY_PROPERTIES;
import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO;
import static com.android.internal.telephony.TelephonyStatsLog.GBA_EVENT;
@@ -36,7 +39,9 @@
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS;
+import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_CONFIG_UPDATER;
import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_CONTROLLER;
+import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_ENTITLEMENT;
import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_INCOMING_DATAGRAM;
import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_OUTGOING_DATAGRAM;
import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_PROVISION;
@@ -69,9 +74,12 @@
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.EmergencyNumbersInfo;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
@@ -87,7 +95,9 @@
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteOutgoingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteProvision;
@@ -138,14 +148,6 @@
private static final long MIN_COOLDOWN_MILLIS =
DBG ? 10L * MILLIS_PER_SECOND : 23L * MILLIS_PER_HOUR;
- /**
- * Sets atom pull cool down to 4 minutes for userdebug build.
- *
- * <p>Applies to certain atoms: CellularServiceState.
- */
- private static final long CELL_SERVICE_MIN_COOLDOWN_MILLIS =
- DBG ? 10L * MILLIS_PER_SECOND :
- IS_DEBUGGABLE ? 4L * MILLIS_PER_MINUTE : 23L * MILLIS_PER_HOUR;
/**
* Buckets with less than these many calls will be dropped.
@@ -166,6 +168,13 @@
private static final long CELL_SERVICE_DURATION_BUCKET_MILLIS =
DBG || IS_DEBUGGABLE ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE;
+ /**
+ * Sets atom pull cool down to 4 minutes for userdebug build, 5 hours for user build.
+ *
+ * <p>Applies to certain atoms: CellularServiceState, DataCallSession,
+ * ImsRegistrationTermination.
+ */
+ private final long mPowerCorrelatedMinCooldownMillis;
private final PersistAtomsStorage mStorage;
private final DeviceStateHelper mDeviceStateHelper;
private final StatsManager mStatsManager;
@@ -177,14 +186,15 @@
public MetricsCollector(Context context, @NonNull FeatureFlags featureFlags) {
this(context, new PersistAtomsStorage(context),
- new DeviceStateHelper(context), new VonrHelper(featureFlags), featureFlags);
+ new DeviceStateHelper(context), new VonrHelper(featureFlags),
+ new DefaultNetworkMonitor(context, featureFlags), featureFlags);
}
/** Allows dependency injection. Used during unit tests. */
@VisibleForTesting
- public MetricsCollector(
- Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper,
- VonrHelper vonrHelper, @NonNull FeatureFlags featureFlags) {
+ public MetricsCollector(Context context, PersistAtomsStorage storage,
+ DeviceStateHelper deviceStateHelper, VonrHelper vonrHelper,
+ DefaultNetworkMonitor defaultNetworkMonitor, @NonNull FeatureFlags featureFlags) {
mStorage = storage;
mDeviceStateHelper = deviceStateHelper;
mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
@@ -227,6 +237,11 @@
registerAtom(SATELLITE_OUTGOING_DATAGRAM);
registerAtom(SATELLITE_PROVISION);
registerAtom(SATELLITE_SOS_MESSAGE_RECOMMENDER);
+ registerAtom(DATA_NETWORK_VALIDATION);
+ registerAtom(CARRIER_ROAMING_SATELLITE_SESSION);
+ registerAtom(CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS);
+ registerAtom(SATELLITE_ENTITLEMENT);
+ registerAtom(SATELLITE_CONFIG_UPDATER);
Rlog.d(TAG, "registered");
} else {
Rlog.e(TAG, "could not get StatsManager, atoms not registered");
@@ -234,6 +249,9 @@
mAirplaneModeStats = new AirplaneModeStats(context);
mDefaultNetworkMonitor = new DefaultNetworkMonitor(context, featureFlags);
+ mPowerCorrelatedMinCooldownMillis = DBG ? 10L * MILLIS_PER_SECOND :
+ IS_DEBUGGABLE ? 4L * MILLIS_PER_MINUTE : (long) context.getResources().getInteger(
+ com.android.internal.R.integer.config_metrics_pull_cooldown_millis);
}
/**
@@ -318,6 +336,16 @@
return pullSatelliteProvision(data);
case SATELLITE_SOS_MESSAGE_RECOMMENDER:
return pullSatelliteSosMessageRecommender(data);
+ case DATA_NETWORK_VALIDATION:
+ return pullDataNetworkValidation(data);
+ case CARRIER_ROAMING_SATELLITE_SESSION:
+ return pullCarrierRoamingSatelliteSession(data);
+ case CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS:
+ return pullCarrierRoamingSatelliteControllerStats(data);
+ case SATELLITE_ENTITLEMENT:
+ return pullSatelliteEntitlement(data);
+ case SATELLITE_CONFIG_UPDATER:
+ return pullSatelliteConfigUpdater(data);
default:
Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag));
return StatsManager.PULL_SKIP;
@@ -516,7 +544,8 @@
private int pullDataCallSession(List<StatsEvent> data) {
// Include ongoing data call segments
concludeDataCallSessionStats();
- DataCallSession[] dataCallSessions = mStorage.getDataCallSessions(MIN_COOLDOWN_MILLIS);
+ DataCallSession[] dataCallSessions = mStorage.getDataCallSessions(
+ mPowerCorrelatedMinCooldownMillis);
if (dataCallSessions != null) {
Arrays.stream(dataCallSessions)
.forEach(dataCall -> data.add(buildStatsEvent(dataCall)));
@@ -544,8 +573,8 @@
private int pullCellularServiceState(List<StatsEvent> data) {
// Include the latest durations
concludeServiceStateStats();
- CellularServiceState[] persistAtoms =
- mStorage.getCellularServiceStates(CELL_SERVICE_MIN_COOLDOWN_MILLIS);
+ CellularServiceState[] persistAtoms = mStorage.getCellularServiceStates(
+ mPowerCorrelatedMinCooldownMillis);
if (persistAtoms != null) {
// list is already shuffled when instances were inserted
Arrays.stream(persistAtoms)
@@ -573,8 +602,8 @@
}
private int pullImsRegistrationTermination(List<StatsEvent> data) {
- ImsRegistrationTermination[] persistAtoms =
- mStorage.getImsRegistrationTerminations(MIN_COOLDOWN_MILLIS);
+ ImsRegistrationTermination[] persistAtoms = mStorage.getImsRegistrationTerminations(
+ mPowerCorrelatedMinCooldownMillis);
if (persistAtoms != null) {
// list is already shuffled when instances were inserted
Arrays.stream(persistAtoms)
@@ -937,6 +966,72 @@
}
}
+ private int pullDataNetworkValidation(@NonNull List<StatsEvent> data) {
+ DataNetworkValidation[] dataNetworkValidations =
+ mStorage.getDataNetworkValidation(mPowerCorrelatedMinCooldownMillis);
+ if (dataNetworkValidations != null) {
+ Arrays.stream(dataNetworkValidations)
+ .forEach(d -> data.add(buildStatsEvent(d)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "DATA_NETWORK_VALIDATION pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
+ private int pullCarrierRoamingSatelliteSession(List<StatsEvent> data) {
+ CarrierRoamingSatelliteSession[] carrierRoamingSatelliteSessionAtoms =
+ mStorage.getCarrierRoamingSatelliteSessionStats(MIN_COOLDOWN_MILLIS);
+ if (carrierRoamingSatelliteSessionAtoms != null) {
+ Arrays.stream(carrierRoamingSatelliteSessionAtoms)
+ .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "CARRIER_ROAMING_SATELLITE_SESSION pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
+ private int pullCarrierRoamingSatelliteControllerStats(List<StatsEvent> data) {
+ CarrierRoamingSatelliteControllerStats[] carrierRoamingSatelliteControllerStatsAtoms =
+ mStorage.getCarrierRoamingSatelliteControllerStats(MIN_COOLDOWN_MILLIS);
+ if (carrierRoamingSatelliteControllerStatsAtoms != null) {
+ Arrays.stream(carrierRoamingSatelliteControllerStatsAtoms)
+ .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS "
+ + "pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
+ private int pullSatelliteEntitlement(List<StatsEvent> data) {
+ SatelliteEntitlement[] satelliteEntitlementAtoms =
+ mStorage.getSatelliteEntitlementStats(MIN_COOLDOWN_MILLIS);
+ if (satelliteEntitlementAtoms != null) {
+ Arrays.stream(satelliteEntitlementAtoms)
+ .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "SATELLITE_ENTITLEMENT pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
+ private int pullSatelliteConfigUpdater(List<StatsEvent> data) {
+ SatelliteConfigUpdater[] satelliteConfigUpdaterAtoms =
+ mStorage.getSatelliteConfigUpdaterStats(MIN_COOLDOWN_MILLIS);
+ if (satelliteConfigUpdaterAtoms != null) {
+ Arrays.stream(satelliteConfigUpdaterAtoms)
+ .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
+ return StatsManager.PULL_SUCCESS;
+ } else {
+ Rlog.w(TAG, "SATELLITE_CONFIG_UPDATER pull too frequent, skipping");
+ return StatsManager.PULL_SKIP;
+ }
+ }
+
/** Registers a pulled atom ID {@code atomId}. */
private void registerAtom(int atomId) {
mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null,
@@ -1110,7 +1205,8 @@
dataCallSession.handoverFailureRat,
dataCallSession.isNonDds,
dataCallSession.isIwlanCrossSim,
- dataCallSession.isNtn);
+ dataCallSession.isNtn,
+ dataCallSession.isSatelliteTransport);
}
private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
@@ -1414,6 +1510,69 @@
stats.isSatelliteAllowedInCurrentLocation);
}
+ private static StatsEvent buildStatsEvent(DataNetworkValidation stats) {
+ return TelephonyStatsLog.buildStatsEvent(
+ DATA_NETWORK_VALIDATION,
+ stats.networkType,
+ stats.apnTypeBitmask,
+ stats.signalStrength,
+ stats.validationResult,
+ stats.elapsedTimeInMillis,
+ stats.handoverAttempted,
+ stats.networkValidationCount);
+ }
+
+ private static StatsEvent buildStatsEvent(CarrierRoamingSatelliteSession stats) {
+ return TelephonyStatsLog.buildStatsEvent(
+ CARRIER_ROAMING_SATELLITE_SESSION,
+ stats.carrierId,
+ stats.isNtnRoamingInHomeCountry,
+ stats.totalSatelliteModeTimeSec,
+ stats.numberOfSatelliteConnections,
+ stats.avgDurationOfSatelliteConnectionSec,
+ stats.satelliteConnectionGapMinSec,
+ stats.satelliteConnectionGapAvgSec,
+ stats.satelliteConnectionGapMaxSec,
+ stats.rsrpAvg,
+ stats.rsrpMedian,
+ stats.rssnrAvg,
+ stats.rssnrMedian,
+ stats.countOfIncomingSms,
+ stats.countOfOutgoingSms,
+ stats.countOfIncomingMms,
+ stats.countOfOutgoingMms);
+ }
+
+ private static StatsEvent buildStatsEvent(CarrierRoamingSatelliteControllerStats stats) {
+ return TelephonyStatsLog.buildStatsEvent(
+ CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS,
+ stats.configDataSource,
+ stats.countOfEntitlementStatusQueryRequest,
+ stats.countOfSatelliteConfigUpdateRequest,
+ stats.countOfSatelliteNotificationDisplayed,
+ stats.satelliteSessionGapMinSec,
+ stats.satelliteSessionGapAvgSec,
+ stats.satelliteSessionGapMaxSec);
+ }
+
+ private static StatsEvent buildStatsEvent(SatelliteEntitlement stats) {
+ return TelephonyStatsLog.buildStatsEvent(
+ SATELLITE_ENTITLEMENT,
+ stats.carrierId,
+ stats.result,
+ stats.entitlementStatus,
+ stats.isRetry,
+ stats.count);
+ }
+
+ private static StatsEvent buildStatsEvent(SatelliteConfigUpdater stats) {
+ return TelephonyStatsLog.buildStatsEvent(SATELLITE_CONFIG_UPDATER,
+ stats.configVersion,
+ stats.oemConfigResult,
+ stats.carrierConfigResult,
+ stats.count);
+ }
+
/** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
static Phone[] getPhonesIfAny() {
try {
diff --git a/src/java/com/android/internal/telephony/metrics/NetworkRequestsStats.java b/src/java/com/android/internal/telephony/metrics/NetworkRequestsStats.java
index 26c28f0..6f4a1a0 100644
--- a/src/java/com/android/internal/telephony/metrics/NetworkRequestsStats.java
+++ b/src/java/com/android/internal/telephony/metrics/NetworkRequestsStats.java
@@ -59,6 +59,47 @@
networkRequestsTemplate.capability = NetworkRequestsV2.NetworkCapability.ENTERPRISE;
storage.addNetworkRequestsV2(networkRequestsTemplate);
}
+
+ if (networkRequest.hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)
+ && !networkRequest.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_INTERNET_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_MMS_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_IMS_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_XCAP_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_EIMS_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+
+ if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
+ networkRequestsTemplate.capability =
+ NetworkRequestsV2.NetworkCapability.SATELLITE_SUPL_RESTRICTED;
+ storage.addNetworkRequestsV2(networkRequestsTemplate);
+ }
+ }
}
/** Returns the carrier ID of the given subscription id. */
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index 979777b..a3e70c9 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -30,9 +30,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent;
@@ -48,7 +51,9 @@
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteOutgoingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteProvision;
@@ -172,6 +177,10 @@
/** Maximum number of Satellite relevant stats to store between pulls. */
private final int mMaxNumSatelliteStats;
private final int mMaxNumSatelliteControllerStats = 1;
+ private final int mMaxNumCarrierRoamingSatelliteSessionStats = 1;
+
+ /** Maximum number of data network validation to store during pulls. */
+ private final int mMaxNumDataNetworkValidation;
/** Stores persist atoms and persist states of the puller. */
@VisibleForTesting protected PersistAtoms mAtoms;
@@ -223,6 +232,7 @@
mMaxNumGbaEventStats = 5;
mMaxOutgoingShortCodeSms = 5;
mMaxNumSatelliteStats = 5;
+ mMaxNumDataNetworkValidation = 5;
} else {
mMaxNumVoiceCallSessions = 50;
mMaxNumSms = 25;
@@ -247,6 +257,7 @@
mMaxNumGbaEventStats = 10;
mMaxOutgoingShortCodeSms = 10;
mMaxNumSatelliteStats = 15;
+ mMaxNumDataNetworkValidation = 15;
}
mAtoms = loadAtomsFromFile();
@@ -807,6 +818,82 @@
saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
}
+ /** Adds a data network validation to the storage. */
+ public synchronized void addDataNetworkValidation(DataNetworkValidation dataNetworkValidation) {
+ DataNetworkValidation existingStats = find(dataNetworkValidation);
+ if (existingStats != null) {
+ int count = existingStats.networkValidationCount
+ + dataNetworkValidation.networkValidationCount;
+ long elapsedTime = ((dataNetworkValidation.elapsedTimeInMillis
+ * dataNetworkValidation.networkValidationCount) + (
+ existingStats.elapsedTimeInMillis * existingStats.networkValidationCount))
+ / count;
+ existingStats.networkValidationCount = count;
+ existingStats.elapsedTimeInMillis = elapsedTime;
+ } else {
+ mAtoms.dataNetworkValidation = insertAtRandomPlace(
+ mAtoms.dataNetworkValidation, dataNetworkValidation, mMaxNumDataCallSessions);
+ }
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
+ /** Adds a new {@link CarrierRoamingSatelliteSession} to the storage. */
+ public synchronized void addCarrierRoamingSatelliteSessionStats(
+ CarrierRoamingSatelliteSession stats) {
+ mAtoms.carrierRoamingSatelliteSession = insertAtRandomPlace(
+ mAtoms.carrierRoamingSatelliteSession, stats,
+ mMaxNumCarrierRoamingSatelliteSessionStats);
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
+ /** Adds a new {@link CarrierRoamingSatelliteControllerStats} to the storage. */
+ public synchronized void addCarrierRoamingSatelliteControllerStats(
+ CarrierRoamingSatelliteControllerStats stats) {
+ // CarrierRoamingSatelliteController is a single data point
+ CarrierRoamingSatelliteControllerStats[] atomArray =
+ mAtoms.carrierRoamingSatelliteControllerStats;
+ if (atomArray == null || atomArray.length == 0) {
+ atomArray = new CarrierRoamingSatelliteControllerStats[] {new
+ CarrierRoamingSatelliteControllerStats()};
+ }
+
+ CarrierRoamingSatelliteControllerStats atom = atomArray[0];
+ atom.configDataSource = stats.configDataSource;
+ atom.countOfEntitlementStatusQueryRequest += stats.countOfEntitlementStatusQueryRequest;
+ atom.countOfSatelliteConfigUpdateRequest += stats.countOfSatelliteConfigUpdateRequest;
+ atom.countOfSatelliteNotificationDisplayed += stats.countOfSatelliteNotificationDisplayed;
+ atom.satelliteSessionGapMinSec = stats.satelliteSessionGapMinSec;
+ atom.satelliteSessionGapAvgSec = stats.satelliteSessionGapAvgSec;
+ atom.satelliteSessionGapMaxSec = stats.satelliteSessionGapMaxSec;
+
+ mAtoms.carrierRoamingSatelliteControllerStats = atomArray;
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
+ /** Adds a new {@link SatelliteEntitlement} to the storage. */
+ public synchronized void addSatelliteEntitlementStats(SatelliteEntitlement stats) {
+ SatelliteEntitlement existingStats = find(stats);
+ if (existingStats != null) {
+ existingStats.count += 1;
+ } else {
+ mAtoms.satelliteEntitlement = insertAtRandomPlace(mAtoms.satelliteEntitlement,
+ stats, mMaxNumSatelliteStats);
+ }
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
+ /** Adds a new {@link SatelliteConfigUpdater} to the storage. */
+ public synchronized void addSatelliteConfigUpdaterStats(SatelliteConfigUpdater stats) {
+ SatelliteConfigUpdater existingStats = find(stats);
+ if (existingStats != null) {
+ existingStats.count += 1;
+ } else {
+ mAtoms.satelliteConfigUpdater = insertAtRandomPlace(mAtoms.satelliteConfigUpdater,
+ stats, mMaxNumSatelliteStats);
+ }
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
+ }
+
/**
* Returns and clears the voice call sessions if last pulled longer than {@code
* minIntervalMillis} ago, otherwise returns {@code null}.
@@ -1465,6 +1552,102 @@
}
}
+ /**
+ * Returns and clears the data network validation if last pulled longer than {@code
+ * minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized DataNetworkValidation[] getDataNetworkValidation(long minIntervalMillis) {
+ long wallTime = getWallTimeMillis();
+ if (wallTime - mAtoms.dataNetworkValidationPullTimestampMillis > minIntervalMillis) {
+ mAtoms.dataNetworkValidationPullTimestampMillis = wallTime;
+ DataNetworkValidation[] previousDataNetworkValidation = mAtoms.dataNetworkValidation;
+ mAtoms.dataNetworkValidation = new DataNetworkValidation[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return previousDataNetworkValidation;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns and clears the {@link CarrierRoamingSatelliteSession} stats if last pulled
+ * longer than {@code minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized CarrierRoamingSatelliteSession[] getCarrierRoamingSatelliteSessionStats(
+ long minIntervalMillis) {
+ if (getWallTimeMillis() - mAtoms.carrierRoamingSatelliteSessionPullTimestampMillis
+ > minIntervalMillis) {
+ mAtoms.carrierRoamingSatelliteSessionPullTimestampMillis = getWallTimeMillis();
+ CarrierRoamingSatelliteSession[] statsArray = mAtoms.carrierRoamingSatelliteSession;
+ mAtoms.carrierRoamingSatelliteSession = new CarrierRoamingSatelliteSession[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return statsArray;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns and clears the {@link CarrierRoamingSatelliteControllerStats} stats if last pulled
+ * longer than {@code minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized CarrierRoamingSatelliteControllerStats[]
+ getCarrierRoamingSatelliteControllerStats(long minIntervalMillis) {
+ if (getWallTimeMillis() - mAtoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis
+ > minIntervalMillis) {
+ mAtoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis = getWallTimeMillis();
+ CarrierRoamingSatelliteControllerStats[] statsArray =
+ mAtoms.carrierRoamingSatelliteControllerStats;
+ mAtoms.carrierRoamingSatelliteControllerStats =
+ new CarrierRoamingSatelliteControllerStats[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return statsArray;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns and clears the {@link SatelliteEntitlement} stats if last pulled longer than {@code
+ * minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized SatelliteEntitlement[] getSatelliteEntitlementStats(
+ long minIntervalMillis) {
+ if (getWallTimeMillis() - mAtoms.satelliteEntitlementPullTimestampMillis
+ > minIntervalMillis) {
+ mAtoms.satelliteEntitlementPullTimestampMillis = getWallTimeMillis();
+ SatelliteEntitlement[] statsArray = mAtoms.satelliteEntitlement;
+ mAtoms.satelliteEntitlement = new SatelliteEntitlement[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return statsArray;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns and clears the {@link SatelliteConfigUpdater} stats if last pulled longer than {@code
+ * minIntervalMillis} ago, otherwise returns {@code null}.
+ */
+ @Nullable
+ public synchronized SatelliteConfigUpdater[] getSatelliteConfigUpdaterStats(
+ long minIntervalMillis) {
+ if (getWallTimeMillis() - mAtoms.satelliteConfigUpdaterPullTimestampMillis
+ > minIntervalMillis) {
+ mAtoms.satelliteConfigUpdaterPullTimestampMillis = getWallTimeMillis();
+ SatelliteConfigUpdater[] statsArray = mAtoms.satelliteConfigUpdater;
+ mAtoms.satelliteConfigUpdater = new SatelliteConfigUpdater[0];
+ saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
+ return statsArray;
+ } else {
+ return null;
+ }
+ }
+
/** Saves {@link PersistAtoms} to a file in private storage immediately. */
public synchronized void flushAtoms() {
saveAtomsToFile(0);
@@ -1615,6 +1798,22 @@
atoms.satelliteSosMessageRecommender = sanitizeAtoms(
atoms.satelliteSosMessageRecommender, SatelliteSosMessageRecommender.class,
mMaxNumSatelliteStats);
+ atoms.dataNetworkValidation =
+ sanitizeAtoms(
+ atoms.dataNetworkValidation,
+ DataNetworkValidation.class,
+ mMaxNumDataNetworkValidation
+ );
+ atoms.carrierRoamingSatelliteSession = sanitizeAtoms(
+ atoms.carrierRoamingSatelliteSession, CarrierRoamingSatelliteSession.class,
+ mMaxNumSatelliteStats);
+ atoms.carrierRoamingSatelliteControllerStats = sanitizeAtoms(
+ atoms.carrierRoamingSatelliteControllerStats,
+ CarrierRoamingSatelliteControllerStats.class, mMaxNumSatelliteControllerStats);
+ atoms.satelliteEntitlement = sanitizeAtoms(atoms.satelliteEntitlement,
+ SatelliteEntitlement.class, mMaxNumSatelliteStats);
+ atoms.satelliteConfigUpdater = sanitizeAtoms(atoms.satelliteConfigUpdater,
+ SatelliteConfigUpdater.class, mMaxNumSatelliteStats);
// out of caution, sanitize also the timestamps
atoms.voiceCallRatUsagePullTimestampMillis =
@@ -1677,6 +1876,16 @@
sanitizeTimestamp(atoms.satelliteProvisionPullTimestampMillis);
atoms.satelliteSosMessageRecommenderPullTimestampMillis =
sanitizeTimestamp(atoms.satelliteSosMessageRecommenderPullTimestampMillis);
+ atoms.dataNetworkValidationPullTimestampMillis =
+ sanitizeTimestamp(atoms.dataNetworkValidationPullTimestampMillis);
+ atoms.carrierRoamingSatelliteSessionPullTimestampMillis = sanitizeTimestamp(
+ atoms.carrierRoamingSatelliteSessionPullTimestampMillis);
+ atoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis = sanitizeTimestamp(
+ atoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis);
+ atoms.satelliteEntitlementPullTimestampMillis =
+ sanitizeTimestamp(atoms.satelliteEntitlementPullTimestampMillis);
+ atoms.satelliteConfigUpdaterPullTimestampMillis =
+ sanitizeTimestamp(atoms.satelliteConfigUpdaterPullTimestampMillis);
return atoms;
} catch (NoSuchFileException e) {
Rlog.d(TAG, "PersistAtoms file not found");
@@ -2112,6 +2321,53 @@
}
/**
+ * Returns SatelliteOutgoingDatagram atom that has same values or {@code null}
+ * if it does not exist.
+ */
+ private @Nullable DataNetworkValidation find(DataNetworkValidation key) {
+ for (DataNetworkValidation stats : mAtoms.dataNetworkValidation) {
+ if (stats.networkType == key.networkType
+ && stats.apnTypeBitmask == key.apnTypeBitmask
+ && stats.signalStrength == key.signalStrength
+ && stats.validationResult == key.validationResult
+ && stats.handoverAttempted == key.handoverAttempted) {
+ return stats;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns SatelliteEntitlement atom that has same values or {@code null} if it does not exist.
+ */
+ private @Nullable SatelliteEntitlement find(SatelliteEntitlement key) {
+ for (SatelliteEntitlement stats : mAtoms.satelliteEntitlement) {
+ if (stats.carrierId == key.carrierId
+ && stats.result == key.result
+ && stats.entitlementStatus == key.entitlementStatus
+ && stats.isRetry == key.isRetry) {
+ return stats;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns SatelliteConfigUpdater atom that has same values
+ * or {@code null} if it does not exist.
+ */
+ private @Nullable SatelliteConfigUpdater find(SatelliteConfigUpdater key) {
+ for (SatelliteConfigUpdater stats : mAtoms.satelliteConfigUpdater) {
+ if (stats.configVersion == key.configVersion
+ && stats.oemConfigResult == key.oemConfigResult
+ && stats.carrierConfigResult == key.carrierConfigResult) {
+ return stats;
+ }
+ }
+ return null;
+ }
+
+ /**
* Inserts a new element in a random position in an array with a maximum size.
*
* <p>If the array is full, merge with existing item if possible or replace one item randomly.
@@ -2367,6 +2623,11 @@
atoms.satelliteOutgoingDatagramPullTimestampMillis = currentTime;
atoms.satelliteProvisionPullTimestampMillis = currentTime;
atoms.satelliteSosMessageRecommenderPullTimestampMillis = currentTime;
+ atoms.dataNetworkValidationPullTimestampMillis = currentTime;
+ atoms.carrierRoamingSatelliteSessionPullTimestampMillis = currentTime;
+ atoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis = currentTime;
+ atoms.satelliteEntitlementPullTimestampMillis = currentTime;
+ atoms.satelliteConfigUpdaterPullTimestampMillis = currentTime;
Rlog.d(TAG, "created new PersistAtoms");
return atoms;
diff --git a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
index a9aab58..2bf035e 100644
--- a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
+++ b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
@@ -19,14 +19,22 @@
import android.telephony.satellite.SatelliteManager;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteOutgoingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteProvision;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteSession;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteSosMessageRecommender;
+import com.android.internal.telephony.satellite.SatelliteConstants;
import com.android.telephony.Rlog;
+import java.util.ArrayList;
+import java.util.List;
+
/** Tracks Satellite metrics for each phone */
public class SatelliteStats {
private static final String TAG = SatelliteStats.class.getSimpleName();
@@ -1206,6 +1214,691 @@
}
}
+ /**
+ * A data class to contain whole component of {@link CarrierRoamingSatelliteSession} atom.
+ * Refer to {@link #onCarrierRoamingSatelliteSessionMetrics(
+ * CarrierRoamingSatelliteSessionParams)}.
+ */
+ public class CarrierRoamingSatelliteSessionParams {
+ private final int mCarrierId;
+ private final boolean mIsNtnRoamingInHomeCountry;
+ private final int mTotalSatelliteModeTimeSec;
+ private final int mNumberOfSatelliteConnections;
+ private final int mAvgDurationOfSatelliteConnectionSec;
+ private final int mSatelliteConnectionGapMinSec;
+ private final int mSatelliteConnectionGapAvgSec;
+ private final int mSatelliteConnectionGapMaxSec;
+ private final int mRsrpAvg;
+ private final int mRsrpMedian;
+ private final int mRssnrAvg;
+ private final int mRssnrMedian;
+ private final int mCountOfIncomingSms;
+ private final int mCountOfOutgoingSms;
+ private final int mCountOfIncomingMms;
+ private final int mCountOfOutgoingMms;
+
+ private CarrierRoamingSatelliteSessionParams(Builder builder) {
+ this.mCarrierId = builder.mCarrierId;
+ this.mIsNtnRoamingInHomeCountry = builder.mIsNtnRoamingInHomeCountry;
+ this.mTotalSatelliteModeTimeSec = builder.mTotalSatelliteModeTimeSec;
+ this.mNumberOfSatelliteConnections = builder.mNumberOfSatelliteConnections;
+ this.mAvgDurationOfSatelliteConnectionSec =
+ builder.mAvgDurationOfSatelliteConnectionSec;
+ this.mSatelliteConnectionGapMinSec = builder.mSatelliteConnectionGapMinSec;
+ this.mSatelliteConnectionGapAvgSec = builder.mSatelliteConnectionGapAvgSec;
+ this.mSatelliteConnectionGapMaxSec = builder.mSatelliteConnectionGapMaxSec;
+ this.mRsrpAvg = builder.mRsrpAvg;
+ this.mRsrpMedian = builder.mRsrpMedian;
+ this.mRssnrAvg = builder.mRssnrAvg;
+ this.mRssnrMedian = builder.mRssnrMedian;
+ this.mCountOfIncomingSms = builder.mCountOfIncomingSms;
+ this.mCountOfOutgoingSms = builder.mCountOfOutgoingSms;
+ this.mCountOfIncomingMms = builder.mCountOfIncomingMms;
+ this.mCountOfOutgoingMms = builder.mCountOfOutgoingMms;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ public boolean getIsNtnRoamingInHomeCountry() {
+ return mIsNtnRoamingInHomeCountry;
+ }
+
+ public int getTotalSatelliteModeTimeSec() {
+ return mTotalSatelliteModeTimeSec;
+ }
+
+ public int getNumberOfSatelliteConnections() {
+ return mNumberOfSatelliteConnections;
+ }
+
+ public int getAvgDurationOfSatelliteConnectionSec() {
+ return mAvgDurationOfSatelliteConnectionSec;
+ }
+
+ public int getSatelliteConnectionGapMinSec() {
+ return mSatelliteConnectionGapMinSec;
+ }
+
+ public int getSatelliteConnectionGapAvgSec() {
+ return mSatelliteConnectionGapAvgSec;
+ }
+
+ public int getSatelliteConnectionGapMaxSec() {
+ return mSatelliteConnectionGapMaxSec;
+ }
+
+ public int getRsrpAvg() {
+ return mRsrpAvg;
+ }
+
+ public int getRsrpMedian() {
+ return mRsrpMedian;
+ }
+
+ public int getRssnrAvg() {
+ return mRssnrAvg;
+ }
+
+ public int getRssnrMedian() {
+ return mRssnrMedian;
+ }
+
+ public int getCountOfIncomingSms() {
+ return mCountOfIncomingSms;
+ }
+
+ public int getCountOfOutgoingSms() {
+ return mCountOfOutgoingSms;
+ }
+
+ public int getCountOfIncomingMms() {
+ return mCountOfIncomingMms;
+ }
+
+ public int getCountOfOutgoingMms() {
+ return mCountOfOutgoingMms;
+ }
+
+ /**
+ * A builder class to create {@link CarrierRoamingSatelliteSessionParams} data structure
+ * class
+ */
+ public static class Builder {
+ private int mCarrierId = -1;
+ private boolean mIsNtnRoamingInHomeCountry = false;
+ private int mTotalSatelliteModeTimeSec = 0;
+ private int mNumberOfSatelliteConnections = 0;
+ private int mAvgDurationOfSatelliteConnectionSec = 0;
+ private int mSatelliteConnectionGapMinSec = 0;
+ private int mSatelliteConnectionGapAvgSec = 0;
+ private int mSatelliteConnectionGapMaxSec = 0;
+ private int mRsrpAvg = 0;
+ private int mRsrpMedian = 0;
+ private int mRssnrAvg = 0;
+ private int mRssnrMedian = 0;
+ private int mCountOfIncomingSms = 0;
+ private int mCountOfOutgoingSms = 0;
+ private int mCountOfIncomingMms = 0;
+ private int mCountOfOutgoingMms = 0;
+
+ /**
+ * Sets carrierId value of {@link CarrierRoamingSatelliteSession} atom
+ * then returns Builder class
+ */
+ public Builder setCarrierId(int carrierId) {
+ this.mCarrierId = carrierId;
+ return this;
+ }
+
+ /**
+ * Sets isNtnRoamingInHomeCountry value of {@link CarrierRoamingSatelliteSession} atom
+ * then returns Builder class
+ */
+ public Builder setIsNtnRoamingInHomeCountry(boolean isNtnRoamingInHomeCountry) {
+ this.mIsNtnRoamingInHomeCountry = isNtnRoamingInHomeCountry;
+ return this;
+ }
+
+ /**
+ * Sets totalSatelliteModeTimeSec value of {@link CarrierRoamingSatelliteSession} atom
+ * then returns Builder class
+ */
+ public Builder setTotalSatelliteModeTimeSec(int totalSatelliteModeTimeSec) {
+ this.mTotalSatelliteModeTimeSec = totalSatelliteModeTimeSec;
+ return this;
+ }
+
+
+ /**
+ * Sets numberOfSatelliteConnections value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setNumberOfSatelliteConnections(int numberOfSatelliteConnections) {
+ this.mNumberOfSatelliteConnections = numberOfSatelliteConnections;
+ return this;
+ }
+
+ /**
+ * Sets avgDurationOfSatelliteConnectionSec value of
+ * {@link CarrierRoamingSatelliteSession} atom then returns Builder class
+ */
+ public Builder setAvgDurationOfSatelliteConnectionSec(
+ int avgDurationOfSatelliteConnectionSec) {
+ this.mAvgDurationOfSatelliteConnectionSec = avgDurationOfSatelliteConnectionSec;
+ return this;
+ }
+
+ /**
+ * Sets satelliteConnectionGapMinSec value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setSatelliteConnectionGapMinSec(int satelliteConnectionGapMinSec) {
+ this.mSatelliteConnectionGapMinSec = satelliteConnectionGapMinSec;
+ return this;
+ }
+
+ /**
+ * Sets satelliteConnectionGapAvgSec value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setSatelliteConnectionGapAvgSec(int satelliteConnectionGapAvgSec) {
+ this.mSatelliteConnectionGapAvgSec = satelliteConnectionGapAvgSec;
+ return this;
+ }
+
+ /**
+ * Sets satelliteConnectionGapMaxSec value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setSatelliteConnectionGapMaxSec(int satelliteConnectionGapMaxSec) {
+ this.mSatelliteConnectionGapMaxSec = satelliteConnectionGapMaxSec;
+ return this;
+ }
+
+ /**
+ * Sets rsrpAvg value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setRsrpAvg(int rsrpAvg) {
+ this.mRsrpAvg = rsrpAvg;
+ return this;
+ }
+
+ /**
+ * Sets rsrpMedian value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setRsrpMedian(int rsrpMedian) {
+ this.mRsrpMedian = rsrpMedian;
+ return this;
+ }
+
+ /**
+ * Sets rssnrAvg value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setRssnrAvg(int rssnrAvg) {
+ this.mRssnrAvg = rssnrAvg;
+ return this;
+ }
+
+ /**
+ * Sets rssnrMedian value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setRssnrMedian(int rssnrMedian) {
+ this.mRssnrMedian = rssnrMedian;
+ return this;
+ }
+
+
+ /**
+ * Sets countOfIncomingSms value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setCountOfIncomingSms(int countOfIncomingSms) {
+ this.mCountOfIncomingSms = countOfIncomingSms;
+ return this;
+ }
+
+ /**
+ * Sets countOfOutgoingSms value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setCountOfOutgoingSms(int countOfOutgoingSms) {
+ this.mCountOfOutgoingSms = countOfOutgoingSms;
+ return this;
+ }
+
+ /**
+ * Sets countOfIncomingMms value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setCountOfIncomingMms(int countOfIncomingMms) {
+ this.mCountOfIncomingMms = countOfIncomingMms;
+ return this;
+ }
+
+ /**
+ * Sets countOfOutgoingMms value of {@link CarrierRoamingSatelliteSession}
+ * atom then returns Builder class
+ */
+ public Builder setCountOfOutgoingMms(int countOfOutgoingMms) {
+ this.mCountOfOutgoingMms = countOfOutgoingMms;
+ return this;
+ }
+
+ /**
+ * Returns CarrierRoamingSatelliteSessionParams, which contains whole component of
+ * {@link CarrierRoamingSatelliteSession} atom
+ */
+ public CarrierRoamingSatelliteSessionParams build() {
+ return new SatelliteStats()
+ .new CarrierRoamingSatelliteSessionParams(Builder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CarrierRoamingSatelliteSessionParams("
+ + "carrierId=" + mCarrierId
+ + ", isNtnRoamingInHomeCountry=" + mIsNtnRoamingInHomeCountry
+ + ", totalSatelliteModeTimeSec=" + mTotalSatelliteModeTimeSec
+ + ", numberOfSatelliteConnections=" + mNumberOfSatelliteConnections
+ + ", avgDurationOfSatelliteConnectionSec="
+ + mAvgDurationOfSatelliteConnectionSec
+ + ", satelliteConnectionGapMinSec=" + mSatelliteConnectionGapMinSec
+ + ", satelliteConnectionGapAvgSec=" + mSatelliteConnectionGapAvgSec
+ + ", satelliteConnectionGapMaxSec=" + mSatelliteConnectionGapMaxSec
+ + ", rsrpAvg=" + mRsrpAvg
+ + ", rsrpMedian=" + mRsrpMedian
+ + ", rssnrAvg=" + mRssnrAvg
+ + ", rssnrMedian=" + mRsrpMedian
+ + ", countOfIncomingSms=" + mCountOfIncomingSms
+ + ", countOfOutgoingSms=" + mCountOfOutgoingSms
+ + ", countOfIncomingMms=" + mCountOfIncomingMms
+ + ", countOfOutgoingMms=" + mCountOfOutgoingMms
+ + ")";
+ }
+ }
+
+ /**
+ * A data class to contain whole component of {@link CarrierRoamingSatelliteControllerStats}
+ * atom. Refer to {@link #onCarrierRoamingSatelliteControllerStatsMetrics(
+ * CarrierRoamingSatelliteControllerStatsParams)}.
+ */
+ public class CarrierRoamingSatelliteControllerStatsParams {
+ private final int mConfigDataSource;
+ private final int mCountOfEntitlementStatusQueryRequest;
+ private final int mCountOfSatelliteConfigUpdateRequest;
+ private final int mCountOfSatelliteNotificationDisplayed;
+ private final int mSatelliteSessionGapMinSec;
+ private final int mSatelliteSessionGapAvgSec;
+ private final int mSatelliteSessionGapMaxSec;
+
+ private CarrierRoamingSatelliteControllerStatsParams(Builder builder) {
+ this.mConfigDataSource = builder.mConfigDataSource;
+ this.mCountOfEntitlementStatusQueryRequest =
+ builder.mCountOfEntitlementStatusQueryRequest;
+ this.mCountOfSatelliteConfigUpdateRequest =
+ builder.mCountOfSatelliteConfigUpdateRequest;
+ this.mCountOfSatelliteNotificationDisplayed =
+ builder.mCountOfSatelliteNotificationDisplayed;
+ this.mSatelliteSessionGapMinSec = builder.mSatelliteSessionGapMinSec;
+ this.mSatelliteSessionGapAvgSec = builder.mSatelliteSessionGapAvgSec;
+ this.mSatelliteSessionGapMaxSec = builder.mSatelliteSessionGapMaxSec;
+ }
+
+ public int getConfigDataSource() {
+ return mConfigDataSource;
+ }
+
+
+ public int getCountOfEntitlementStatusQueryRequest() {
+ return mCountOfEntitlementStatusQueryRequest;
+ }
+
+ public int getCountOfSatelliteConfigUpdateRequest() {
+ return mCountOfSatelliteConfigUpdateRequest;
+ }
+
+ public int getCountOfSatelliteNotificationDisplayed() {
+ return mCountOfSatelliteNotificationDisplayed;
+ }
+
+ public int getSatelliteSessionGapMinSec() {
+ return mSatelliteSessionGapMinSec;
+ }
+
+ public int getSatelliteSessionGapAvgSec() {
+ return mSatelliteSessionGapAvgSec;
+ }
+
+ public int getSatelliteSessionGapMaxSec() {
+ return mSatelliteSessionGapMaxSec;
+ }
+
+ /**
+ * A builder class to create {@link CarrierRoamingSatelliteControllerStatsParams}
+ * data structure class
+ */
+ public static class Builder {
+ private int mConfigDataSource = SatelliteConstants.CONFIG_DATA_SOURCE_UNKNOWN;
+ private int mCountOfEntitlementStatusQueryRequest = 0;
+ private int mCountOfSatelliteConfigUpdateRequest = 0;
+ private int mCountOfSatelliteNotificationDisplayed = 0;
+ private int mSatelliteSessionGapMinSec = 0;
+ private int mSatelliteSessionGapAvgSec = 0;
+ private int mSatelliteSessionGapMaxSec = 0;
+
+ /**
+ * Sets configDataSource value of {@link CarrierRoamingSatelliteControllerStats} atom
+ * then returns Builder class
+ */
+ public Builder setConfigDataSource(int configDataSource) {
+ this.mConfigDataSource = configDataSource;
+ return this;
+ }
+
+ /**
+ * Sets countOfEntitlementStatusQueryRequest value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setCountOfEntitlementStatusQueryRequest(
+ int countOfEntitlementStatusQueryRequest) {
+ this.mCountOfEntitlementStatusQueryRequest = countOfEntitlementStatusQueryRequest;
+ return this;
+ }
+
+ /**
+ * Sets countOfSatelliteConfigUpdateRequest value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setCountOfSatelliteConfigUpdateRequest(
+ int countOfSatelliteConfigUpdateRequest) {
+ this.mCountOfSatelliteConfigUpdateRequest = countOfSatelliteConfigUpdateRequest;
+ return this;
+ }
+
+ /**
+ * Sets countOfSatelliteNotificationDisplayed value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setCountOfSatelliteNotificationDisplayed(
+ int countOfSatelliteNotificationDisplayed) {
+ this.mCountOfSatelliteNotificationDisplayed = countOfSatelliteNotificationDisplayed;
+ return this;
+ }
+
+ /**
+ * Sets satelliteSessionGapMinSec value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setSatelliteSessionGapMinSec(int satelliteSessionGapMinSec) {
+ this.mSatelliteSessionGapMinSec = satelliteSessionGapMinSec;
+ return this;
+ }
+
+ /**
+ * Sets satelliteSessionGapAvgSec value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setSatelliteSessionGapAvgSec(int satelliteSessionGapAvgSec) {
+ this.mSatelliteSessionGapAvgSec = satelliteSessionGapAvgSec;
+ return this;
+ }
+
+ /**
+ * Sets satelliteSessionGapMaxSec value of
+ * {@link CarrierRoamingSatelliteControllerStats} atom then returns Builder class
+ */
+ public Builder setSatelliteSessionGapMaxSec(int satelliteSessionGapMaxSec) {
+ this.mSatelliteSessionGapMaxSec = satelliteSessionGapMaxSec;
+ return this;
+ }
+
+ /**
+ * Returns CarrierRoamingSatelliteControllerStatsParams, which contains whole component
+ * of {@link CarrierRoamingSatelliteControllerStats} atom
+ */
+ public CarrierRoamingSatelliteControllerStatsParams build() {
+ return new SatelliteStats()
+ .new CarrierRoamingSatelliteControllerStatsParams(Builder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CarrierRoamingSatelliteControllerStatsParams("
+ + "configDataSource=" + mConfigDataSource
+ + ", countOfEntitlementStatusQueryRequest="
+ + mCountOfEntitlementStatusQueryRequest
+ + ", countOfSatelliteConfigUpdateRequest="
+ + mCountOfSatelliteConfigUpdateRequest
+ + ", countOfSatelliteNotificationDisplayed="
+ + mCountOfSatelliteNotificationDisplayed
+ + ", satelliteSessionGapMinSec=" + mSatelliteSessionGapMinSec
+ + ", satelliteSessionGapAvgSec=" + mSatelliteSessionGapAvgSec
+ + ", satelliteSessionGapMaxSec=" + mSatelliteSessionGapMaxSec
+ + ")";
+ }
+ }
+
+ /**
+ * A data class to contain whole component of {@link SatelliteEntitlement} atom.
+ * Refer to {@link #onSatelliteEntitlementMetrics(SatelliteEntitlementParams)}.
+ */
+ public class SatelliteEntitlementParams {
+ private final int mCarrierId;
+ private final int mResult;
+ private final int mEntitlementStatus;
+ private final boolean mIsRetry;
+ private final int mCount;
+
+ private SatelliteEntitlementParams(Builder builder) {
+ this.mCarrierId = builder.mCarrierId;
+ this.mResult = builder.mResult;
+ this.mEntitlementStatus = builder.mEntitlementStatus;
+ this.mIsRetry = builder.mIsRetry;
+ this.mCount = builder.mCount;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ public int getResult() {
+ return mResult;
+ }
+
+ public int getEntitlementStatus() {
+ return mEntitlementStatus;
+ }
+
+ public boolean getIsRetry() {
+ return mIsRetry;
+ }
+
+ public int getCount() {
+ return mCount;
+ }
+
+ /**
+ * A builder class to create {@link SatelliteEntitlementParams} data structure class
+ */
+ public static class Builder {
+ private int mCarrierId = -1;
+ private int mResult = -1;
+ private int mEntitlementStatus = -1;
+ private boolean mIsRetry = false;
+ private int mCount = -1;
+
+ /**
+ * Sets carrierId value of {@link SatelliteEntitlement} atom
+ * then returns Builder class
+ */
+ public Builder setCarrierId(int carrierId) {
+ this.mCarrierId = carrierId;
+ return this;
+ }
+
+ /**
+ * Sets result value of {@link SatelliteEntitlement} atom
+ * then returns Builder class
+ */
+ public Builder setResult(int result) {
+ this.mResult = result;
+ return this;
+ }
+
+ /**
+ * Sets entitlementStatus value of {@link SatelliteEntitlement} atom
+ * then returns Builder class
+ */
+ public Builder setEntitlementStatus(int entitlementStatus) {
+ this.mEntitlementStatus = entitlementStatus;
+ return this;
+ }
+
+ /**
+ * Sets isRetry value of {@link SatelliteEntitlement} atom
+ * then returns Builder class
+ */
+ public Builder setIsRetry(boolean isRetry) {
+ this.mIsRetry = isRetry;
+ return this;
+ }
+
+ /**
+ * Sets count value of {@link SatelliteEntitlement} atom
+ * then returns Builder class
+ */
+ public Builder setCount(int count) {
+ this.mCount = count;
+ return this;
+ }
+
+ /**
+ * Returns SatelliteEntitlementParams, which contains whole component of
+ * {@link SatelliteEntitlement} atom
+ */
+ public SatelliteEntitlementParams build() {
+ return new SatelliteStats()
+ .new SatelliteEntitlementParams(Builder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SatelliteEntitlementParams("
+ + "carrierId=" + mCarrierId
+ + ", result=" + mResult
+ + ", entitlementStatus=" + mEntitlementStatus
+ + ", isRetry=" + mIsRetry
+ + ", count=" + mCount + ")";
+ }
+ }
+
+ /**
+ * A data class to contain whole component of {@link SatelliteConfigUpdater} atom.
+ * Refer to {@link #onSatelliteConfigUpdaterMetrics(SatelliteConfigUpdaterParams)}.
+ */
+ public class SatelliteConfigUpdaterParams {
+ private final int mConfigVersion;
+ private final int mOemConfigResult;
+ private final int mCarrierConfigResult;
+ private final int mCount;
+
+ private SatelliteConfigUpdaterParams(Builder builder) {
+ this.mConfigVersion = builder.mConfigVersion;
+ this.mOemConfigResult = builder.mOemConfigResult;
+ this.mCarrierConfigResult = builder.mCarrierConfigResult;
+ this.mCount = builder.mCount;
+ }
+
+ public int getConfigVersion() {
+ return mConfigVersion;
+ }
+
+ public int getOemConfigResult() {
+ return mOemConfigResult;
+ }
+
+ public int getCarrierConfigResult() {
+ return mCarrierConfigResult;
+ }
+
+ public int getCount() {
+ return mCount;
+ }
+
+ /**
+ * A builder class to create {@link SatelliteConfigUpdaterParams} data structure class
+ */
+ public static class Builder {
+ private int mConfigVersion = -1;
+ private int mOemConfigResult = -1;
+ private int mCarrierConfigResult = -1;
+ private int mCount = -1;
+
+ /**
+ * Sets configVersion value of {@link SatelliteConfigUpdater} atom
+ * then returns Builder class
+ */
+ public Builder setConfigVersion(int configVersion) {
+ this.mConfigVersion = configVersion;
+ return this;
+ }
+
+ /**
+ * Sets oemConfigResult value of {@link SatelliteConfigUpdater} atom
+ * then returns Builder class
+ */
+ public Builder setOemConfigResult(int oemConfigResult) {
+ this.mOemConfigResult = oemConfigResult;
+ return this;
+ }
+
+ /**
+ * Sets carrierConfigResult value of {@link SatelliteConfigUpdater} atom
+ * then returns Builder class
+ */
+ public Builder setCarrierConfigResult(int carrierConfigResult) {
+ this.mCarrierConfigResult = carrierConfigResult;
+ return this;
+ }
+
+ /**
+ * Sets count value of {@link SatelliteConfigUpdater} atom
+ * then returns Builder class
+ */
+ public Builder setCount(int count) {
+ this.mCount = count;
+ return this;
+ }
+
+ /**
+ * Returns SatelliteConfigUpdaterParams, which contains whole component of
+ * {@link SatelliteConfigUpdater} atom
+ */
+ public SatelliteConfigUpdaterParams build() {
+ return new SatelliteStats()
+ .new SatelliteConfigUpdaterParams(Builder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SatelliteConfigUpdaterParams("
+ + "configVersion=" + mConfigVersion
+ + ", oemConfigResult=" + mOemConfigResult
+ + ", carrierConfigResult=" + mCarrierConfigResult
+ + ", count=" + mCount + ")";
+ }
+ }
+
/** Create a new atom or update an existing atom for SatelliteController metrics */
public synchronized void onSatelliteControllerMetrics(SatelliteControllerParams param) {
SatelliteController proto = new SatelliteController();
@@ -1311,4 +2004,62 @@
proto.count = 1;
mAtomsStorage.addSatelliteSosMessageRecommenderStats(proto);
}
+
+ /** Create a new atom for CarrierRoamingSatelliteSession metrics */
+ public synchronized void onCarrierRoamingSatelliteSessionMetrics(
+ CarrierRoamingSatelliteSessionParams param) {
+ CarrierRoamingSatelliteSession proto = new CarrierRoamingSatelliteSession();
+ proto.carrierId = param.getCarrierId();
+ proto.isNtnRoamingInHomeCountry = param.getIsNtnRoamingInHomeCountry();
+ proto.totalSatelliteModeTimeSec = param.getTotalSatelliteModeTimeSec();
+ proto.numberOfSatelliteConnections = param.getNumberOfSatelliteConnections();
+ proto.avgDurationOfSatelliteConnectionSec = param.getAvgDurationOfSatelliteConnectionSec();
+ proto.satelliteConnectionGapMinSec = param.mSatelliteConnectionGapMinSec;
+ proto.satelliteConnectionGapAvgSec = param.mSatelliteConnectionGapAvgSec;
+ proto.satelliteConnectionGapMaxSec = param.mSatelliteConnectionGapMaxSec;
+ proto.rsrpAvg = param.mRsrpAvg;
+ proto.rsrpMedian = param.mRsrpMedian;
+ proto.rssnrAvg = param.mRssnrAvg;
+ proto.rssnrMedian = param.mRssnrMedian;
+ proto.countOfIncomingSms = param.mCountOfIncomingSms;
+ proto.countOfOutgoingSms = param.mCountOfOutgoingSms;
+ proto.countOfIncomingMms = param.mCountOfIncomingMms;
+ proto.countOfOutgoingMms = param.mCountOfOutgoingMms;
+ mAtomsStorage.addCarrierRoamingSatelliteSessionStats(proto);
+ }
+
+ /** Create a new atom for CarrierRoamingSatelliteSession metrics */
+ public synchronized void onCarrierRoamingSatelliteControllerStatsMetrics(
+ CarrierRoamingSatelliteControllerStatsParams param) {
+ CarrierRoamingSatelliteControllerStats proto = new CarrierRoamingSatelliteControllerStats();
+ proto.configDataSource = param.mConfigDataSource;
+ proto.countOfEntitlementStatusQueryRequest = param.mCountOfEntitlementStatusQueryRequest;
+ proto.countOfSatelliteConfigUpdateRequest = param.mCountOfSatelliteConfigUpdateRequest;
+ proto.countOfSatelliteNotificationDisplayed = param.mCountOfSatelliteNotificationDisplayed;
+ proto.satelliteSessionGapMinSec = param.mSatelliteSessionGapMinSec;
+ proto.satelliteSessionGapAvgSec = param.mSatelliteSessionGapAvgSec;
+ proto.satelliteSessionGapMaxSec = param.mSatelliteSessionGapMaxSec;
+ mAtomsStorage.addCarrierRoamingSatelliteControllerStats(proto);
+ }
+
+ /** Create a new atom for SatelliteEntitlement metrics */
+ public synchronized void onSatelliteEntitlementMetrics(SatelliteEntitlementParams param) {
+ SatelliteEntitlement proto = new SatelliteEntitlement();
+ proto.carrierId = param.getCarrierId();
+ proto.result = param.getResult();
+ proto.entitlementStatus = param.getEntitlementStatus();
+ proto.isRetry = param.getIsRetry();
+ proto.count = param.getCount();
+ mAtomsStorage.addSatelliteEntitlementStats(proto);
+ }
+
+ /** Create a new atom for SatelliteConfigUpdater metrics */
+ public synchronized void onSatelliteConfigUpdaterMetrics(SatelliteConfigUpdaterParams param) {
+ SatelliteConfigUpdater proto = new SatelliteConfigUpdater();
+ proto.configVersion = param.getConfigVersion();
+ proto.oemConfigResult = param.getOemConfigResult();
+ proto.carrierConfigResult = param.getCarrierConfigResult();
+ proto.count = param.getCount();
+ mAtomsStorage.addSatelliteConfigUpdaterStats(proto);
+ }
}
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index d4830ae..3f24968 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -21,6 +21,7 @@
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN;
+import static com.android.internal.telephony.flags.Flags.dataRatMetricEnabled;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,6 +32,7 @@
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RoamingType;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -38,6 +40,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.data.DataNetwork;
import com.android.internal.telephony.data.DataNetworkController;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
@@ -62,6 +65,8 @@
private final PersistAtomsStorage mStorage;
private final DeviceStateHelper mDeviceStateHelper;
private boolean mExistAnyConnectedInternetPdn;
+ private int mCurrentDataRat =
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED;
public ServiceStateStats(Phone phone) {
super(Runnable::run);
@@ -144,6 +149,10 @@
addServiceStateAndSwitch(
prevState, now, getDataServiceSwitch(prevState.mServiceState, newState));
}
+
+ if (dataRatMetricEnabled()) {
+ writeDataRatAtom(serviceState);
+ }
}
/** Updates the fold state of the device for the current service state. */
@@ -461,6 +470,68 @@
|| isNetworkRoaming(ss, NetworkRegistrationInfo.DOMAIN_PS);
}
+ /** Collect data Rat metric. */
+ private void writeDataRatAtom(@NonNull ServiceState serviceState) {
+ if (DataConnectionStateTracker.getActiveDataSubId() != mPhone.getSubId()) {
+ return;
+ }
+ NetworkRegistrationInfo wwanRegInfo = serviceState.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (wwanRegInfo == null) {
+ return;
+ }
+ int dataRat = wwanRegInfo.getAccessNetworkTechnology();
+ int nrFrequency = serviceState.getNrFrequencyRange();
+ int nrState = serviceState.getNrState();
+ int translatedDataRat =
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_UNSPECIFIED;
+ if (!SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+ translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__NO_SIM;
+ } else if (dataRat == TelephonyManager.NETWORK_TYPE_EHRPD
+ || dataRat == TelephonyManager.NETWORK_TYPE_HSPAP
+ || dataRat == TelephonyManager.NETWORK_TYPE_UMTS
+ || dataRat == TelephonyManager.NETWORK_TYPE_HSDPA
+ || dataRat == TelephonyManager.NETWORK_TYPE_HSUPA
+ || dataRat == TelephonyManager.NETWORK_TYPE_HSPA
+ || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_0
+ || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_A
+ || dataRat == TelephonyManager.NETWORK_TYPE_EVDO_B) {
+ translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_3G;
+ } else if (dataRat == TelephonyManager.NETWORK_TYPE_1xRTT
+ || dataRat == TelephonyManager.NETWORK_TYPE_GPRS
+ || dataRat == TelephonyManager.NETWORK_TYPE_EDGE
+ || dataRat == TelephonyManager.NETWORK_TYPE_CDMA
+ || dataRat == TelephonyManager.NETWORK_TYPE_GSM) {
+ translatedDataRat = TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_2G;
+ } else if (dataRat == TelephonyManager.NETWORK_TYPE_NR) {
+ translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE
+ ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR1 :
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_SA_FR2;
+ } else if (dataRat == TelephonyManager.NETWORK_TYPE_LTE) {
+ if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
+ translatedDataRat = nrFrequency != ServiceState.FREQUENCY_RANGE_MMWAVE
+ ? TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR1 :
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_FR2;
+ } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
+ translatedDataRat =
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_5G_NSA_LTE;
+ } else {
+ translatedDataRat =
+ TelephonyStatsLog.DATA_RAT_STATE_CHANGED__DATA_RAT__DATA_RAT_4G_LTE;
+ }
+ }
+
+ if (translatedDataRat != mCurrentDataRat) {
+ TelephonyStatsLog.write(TelephonyStatsLog.DATA_RAT_STATE_CHANGED, translatedDataRat);
+ mCurrentDataRat = translatedDataRat;
+ }
+ }
+
+ int getCurrentDataRat() {
+ return mCurrentDataRat;
+ }
+
@VisibleForTesting
protected long getTimeMillis() {
return SystemClock.elapsedRealtime();
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 8be9e83..c4ad93a 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -797,11 +797,8 @@
}
}
}
- if (bearer == VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS) {
- return TelephonyManager.NETWORK_TYPE_UNKNOWN;
- } else {
- return ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_CS);
- }
+
+ return ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_CS);
}
/** Resets the list of codecs used for the connection with only the codec currently in use. */
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteConstants.java b/src/java/com/android/internal/telephony/satellite/SatelliteConstants.java
new file mode 100644
index 0000000..f88069f
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteConstants.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class SatelliteConstants {
+ public static final int CONFIG_DATA_SOURCE_UNKNOWN = 0;
+ public static final int CONFIG_DATA_SOURCE_ENTITLEMENT = 1;
+ public static final int CONFIG_DATA_SOURCE_CONFIG_UPDATER = 2;
+ public static final int CONFIG_DATA_SOURCE_CARRIER_CONFIG = 3;
+ public static final int CONFIG_DATA_SOURCE_DEVICE_CONFIG = 4;
+
+ @IntDef(prefix = {"CONFIG_DATA_SOURCE_"}, value = {
+ CONFIG_DATA_SOURCE_UNKNOWN,
+ CONFIG_DATA_SOURCE_ENTITLEMENT,
+ CONFIG_DATA_SOURCE_CONFIG_UPDATER,
+ CONFIG_DATA_SOURCE_CARRIER_CONFIG,
+ CONFIG_DATA_SOURCE_DEVICE_CONFIG
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ConfigDataSource {}
+
+ public static final int SATELLITE_ENTITLEMENT_STATUS_UNKNOWN = 0;
+ public static final int SATELLITE_ENTITLEMENT_STATUS_DISABLED = 1;
+ public static final int SATELLITE_ENTITLEMENT_STATUS_ENABLED = 2;
+ public static final int SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE = 3;
+ public static final int SATELLITE_ENTITLEMENT_STATUS_PROVISIONING = 4;
+
+ @IntDef(prefix = {"SATELLITE_ENTITLEMENT_STATUS_"}, value = {
+ SATELLITE_ENTITLEMENT_STATUS_UNKNOWN,
+ SATELLITE_ENTITLEMENT_STATUS_DISABLED,
+ SATELLITE_ENTITLEMENT_STATUS_ENABLED,
+ SATELLITE_ENTITLEMENT_STATUS_INCOMPATIBLE,
+ SATELLITE_ENTITLEMENT_STATUS_PROVISIONING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SatelliteEntitlementStatus {}
+
+ public static final int CONFIG_UPDATE_RESULT_UNKNOWN = 0;
+ public static final int CONFIG_UPDATE_RESULT_SUCCESS = 1;
+ public static final int CONFIG_UPDATE_RESULT_INVALID_DOMAIN = 2;
+ public static final int CONFIG_UPDATE_RESULT_INVALID_VERSION = 3;
+ public static final int CONFIG_UPDATE_RESULT_NO_DATA = 4;
+ public static final int CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA = 5;
+ public static final int CONFIG_UPDATE_RESULT_PARSE_ERROR = 6;
+ public static final int CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_PLMN = 7;
+ public static final int CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_SUPPORTED_SERVICES = 8;
+ public static final int CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE = 9;
+ public static final int CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE = 10;
+ public static final int CONFIG_UPDATE_RESULT_IO_ERROR = 11;
+
+ @IntDef(prefix = {"CONFIG_UPDATE_RESULT_"}, value = {
+ CONFIG_UPDATE_RESULT_UNKNOWN,
+ CONFIG_UPDATE_RESULT_SUCCESS,
+ CONFIG_UPDATE_RESULT_INVALID_DOMAIN,
+ CONFIG_UPDATE_RESULT_INVALID_VERSION,
+ CONFIG_UPDATE_RESULT_NO_DATA,
+ CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA,
+ CONFIG_UPDATE_RESULT_PARSE_ERROR,
+ CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_PLMN,
+ CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_SUPPORTED_SERVICES,
+ CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE,
+ CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE,
+ CONFIG_UPDATE_RESULT_IO_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ConfigUpdateResult {}
+}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 05051fa..8582eaa 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -117,6 +117,8 @@
import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteSessionStats;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
@@ -220,6 +222,7 @@
@NonNull private final ControllerMetricsStats mControllerMetricsStats;
@NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
@NonNull private SessionMetricsStats mSessionMetricsStats;
+ @NonNull private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats;
@NonNull private final SubscriptionManagerService mSubscriptionManagerService;
private final CommandsInterface mCi;
private ContentResolver mContentResolver;
@@ -364,6 +367,10 @@
@GuardedBy("mSatelliteConnectedLock")
@NonNull private final SparseBooleanArray mInitialized = new SparseBooleanArray();
+ @GuardedBy("mSatelliteConnectedLock")
+ @NonNull private final Map<Integer, CarrierRoamingSatelliteSessionStats>
+ mCarrierRoamingSatelliteSessionStatsMap = new HashMap<>();
+
/**
* Key: Subscription ID; Value: set of
* {@link android.telephony.NetworkRegistrationInfo.ServiceType}
@@ -473,6 +480,8 @@
mControllerMetricsStats = ControllerMetricsStats.make(mContext);
mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance();
mSessionMetricsStats = SessionMetricsStats.getInstance();
+ mCarrierRoamingSatelliteControllerStats =
+ CarrierRoamingSatelliteControllerStats.getOrCreateInstance();
mSubscriptionManagerService = SubscriptionManagerService.getInstance();
// Create the DatagramController singleton,
@@ -3614,6 +3623,8 @@
if (!entitlementPlmnList.isEmpty()) {
mMergedPlmnListPerCarrier.put(subId, entitlementPlmnList);
logd("mMergedPlmnListPerCarrier is updated by Entitlement");
+ mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
+ SatelliteConstants.CONFIG_DATA_SOURCE_ENTITLEMENT);
return;
}
}
@@ -3627,6 +3638,8 @@
logd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : "
+ String.join(",", plmnList));
mMergedPlmnListPerCarrier.put(subId, plmnList);
+ mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
+ SatelliteConstants.CONFIG_DATA_SOURCE_CONFIG_UPDATER);
return;
}
}
@@ -3637,6 +3650,8 @@
mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList();
logd("mMergedPlmnListPerCarrier is updated by carrier config: "
+ String.join(",", carrierPlmnList));
+ mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
+ SatelliteConstants.CONFIG_DATA_SOURCE_CARRIER_CONFIG);
} else {
carrierPlmnList = new ArrayList<>();
logd("Empty mMergedPlmnListPerCarrier");
@@ -4113,7 +4128,15 @@
}
synchronized (mSatelliteConnectedLock) {
+ CarrierRoamingSatelliteSessionStats sessionStats =
+ mCarrierRoamingSatelliteSessionStatsMap.get(subId);
+
if (serviceState.isUsingNonTerrestrialNetwork()) {
+ if (sessionStats != null && !mWasSatelliteConnectedViaCarrier.get(subId)) {
+ // Log satellite connection start
+ sessionStats.onConnectionStart();
+ }
+
resetCarrierRoamingSatelliteModeParams(subId);
mWasSatelliteConnectedViaCarrier.put(subId, true);
@@ -4139,6 +4162,11 @@
sendMessageDelayed(obtainMessage(EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT,
phone.getPhoneId()),
getSatelliteConnectionHysteresisTimeMillis(subId));
+
+ if (sessionStats != null) {
+ // Log satellite connection end
+ sessionStats.onConnectionEnd();
+ }
}
mWasSatelliteConnectedViaCarrier.put(subId, false);
}
@@ -4163,6 +4191,27 @@
if (!initialized) mInitialized.put(subId, true);
mLastNotifiedNtnMode.put(subId, currNtnMode);
phone.notifyCarrierRoamingNtnModeChanged(currNtnMode);
+ logCarrierRoamingSatelliteSessionStats(phone, lastNotifiedNtnMode, currNtnMode);
+ }
+ }
+ }
+
+ private void logCarrierRoamingSatelliteSessionStats(@NonNull Phone phone,
+ boolean lastNotifiedNtnMode, boolean currNtnMode) {
+ synchronized (mSatelliteConnectedLock) {
+ int subId = phone.getSubId();
+ if (!lastNotifiedNtnMode && currNtnMode) {
+ // Log satellite session start
+ CarrierRoamingSatelliteSessionStats sessionStats =
+ new CarrierRoamingSatelliteSessionStats(mContext, phone.getCarrierId());
+ sessionStats.onSessionStart();
+ mCarrierRoamingSatelliteSessionStatsMap.put(subId, sessionStats);
+ } else if (lastNotifiedNtnMode && !currNtnMode) {
+ // Log satellite session end
+ CarrierRoamingSatelliteSessionStats sessionStats =
+ mCarrierRoamingSatelliteSessionStatsMap.get(subId);
+ sessionStats.onSessionEnd();
+ mCarrierRoamingSatelliteSessionStatsMap.remove(subId);
}
}
}
@@ -4523,6 +4572,8 @@
notificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
notificationBuilder.build(), UserHandle.ALL);
+
+ mCarrierRoamingSatelliteControllerStats.reportCountOfSatelliteNotificationDisplayed();
}
private void resetCarrierRoamingSatelliteModeParams() {
@@ -4536,7 +4587,6 @@
private void resetCarrierRoamingSatelliteModeParams(int subId) {
if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
- logd("resetCarrierRoamingSatelliteModeParams subId:" + subId);
synchronized (mSatelliteConnectedLock) {
mLastSatelliteDisconnectedTimesMillis.put(subId, null);
mSatModeCapabilitiesForCarrierRoaming.remove(subId);
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteControllerStats.java b/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteControllerStats.java
new file mode 100644
index 0000000..9524b75
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteControllerStats.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite.metrics;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import com.android.internal.telephony.metrics.SatelliteStats;
+import com.android.internal.telephony.satellite.SatelliteConstants;
+
+public class CarrierRoamingSatelliteControllerStats {
+ private static final String TAG = CarrierRoamingSatelliteControllerStats.class.getSimpleName();
+ private static CarrierRoamingSatelliteControllerStats sInstance = null;
+ private static final int ADD_COUNT = 1;
+
+ private SatelliteStats mSatelliteStats;
+
+ private CarrierRoamingSatelliteControllerStats() {
+ mSatelliteStats = SatelliteStats.getInstance();
+ }
+
+ /**
+ * Returns the Singleton instance of CarrierRoamingSatelliteControllerStats class.
+ * If an instance of the Singleton class has not been created,
+ * it creates a new instance and returns it. Otherwise, it returns
+ * the existing instance.
+ * @return the Singleton instance of CarrierRoamingSatelliteControllerStats
+ */
+ public static CarrierRoamingSatelliteControllerStats getOrCreateInstance() {
+ if (sInstance == null) {
+ logd("Create new CarrierRoamingSatelliteControllerStats.");
+ sInstance = new CarrierRoamingSatelliteControllerStats();
+ }
+ return sInstance;
+ }
+
+ /** Report config data source */
+ public void reportConfigDataSource(@SatelliteConstants.ConfigDataSource int configDataSource) {
+ mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics(
+ new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder()
+ .setConfigDataSource(configDataSource)
+ .build());
+ }
+
+ /** Report count of entitlement status query request */
+ public void reportCountOfEntitlementStatusQueryRequest() {
+ mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics(
+ new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder()
+ .setCountOfEntitlementStatusQueryRequest(ADD_COUNT)
+ .build());
+ }
+
+ /** Report count of satellite config update request */
+ public void reportCountOfSatelliteConfigUpdateRequest() {
+ mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics(
+ new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder()
+ .setCountOfSatelliteConfigUpdateRequest(ADD_COUNT)
+ .build());
+ }
+
+ /** Report count of satellite notification displayed */
+ public void reportCountOfSatelliteNotificationDisplayed() {
+ mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics(
+ new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder()
+ .setCountOfSatelliteNotificationDisplayed(ADD_COUNT)
+ .build());
+ }
+
+ private static void logd(@NonNull String log) {
+ Log.d(TAG, log);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteSessionStats.java b/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteSessionStats.java
new file mode 100644
index 0000000..78c5222
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/metrics/CarrierRoamingSatelliteSessionStats.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite.metrics;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.telephony.metrics.SatelliteStats;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CarrierRoamingSatelliteSessionStats {
+ private static final String TAG = CarrierRoamingSatelliteSessionStats.class.getSimpleName();
+ private final Context mContext;
+
+ private int mCarrierId;
+ private boolean mIsNtnRoamingInHomeCountry;
+ private int mRsrpAvg;
+ private int mRsrpMedian;
+ private int mRssnrAvg;
+ private int mRssnrMedian;
+ private int mCountOfIncomingSms;
+ private int mCountOfOutgoingSms;
+ private int mCountOfIncomingMms;
+ private int mCountOfOutgoingMms;
+
+ private int mSessionStartTimeSec;
+ private List<Long> mConnectionStartTimeList;
+ private List<Long> mConnectionEndTimeList;
+
+ public CarrierRoamingSatelliteSessionStats(@NonNull Context context, int carrierId) {
+ logd("Create new CarrierRoamingSatelliteSessionStats.");
+ initializeParams();
+
+ mContext = context;
+ mCarrierId = carrierId;
+ }
+
+ /** Log carrier roaming satellite session start */
+ public void onSessionStart() {
+ mSessionStartTimeSec = getCurrentTimeInSec();
+ onConnectionStart();
+ }
+
+ /** Log carrier roaming satellite connection start */
+ public void onConnectionStart() {
+ mConnectionStartTimeList.add(getCurrentTime());
+ }
+
+ /** Log carrier roaming satellite session end */
+ public void onSessionEnd() {
+ onConnectionEnd();
+ reportMetrics();
+ }
+
+ /** Log carrier roaming satellite connection end */
+ public void onConnectionEnd() {
+ mConnectionEndTimeList.add(getCurrentTime());
+ }
+
+ private void reportMetrics() {
+ int totalSatelliteModeTimeSec = mSessionStartTimeSec > 0
+ ? getCurrentTimeInSec() - mSessionStartTimeSec : 0;
+ int numberOfSatelliteConnections = getNumberOfSatelliteConnections();
+ int avgDurationOfSatelliteConnectionSec = getAvgDurationOfSatelliteConnection(
+ numberOfSatelliteConnections);
+
+ List<Integer> connectionGapList = getSatelliteConnectionGapList(
+ numberOfSatelliteConnections);
+ int satelliteConnectionGapMinSec = 0;
+ int satelliteConnectionGapMaxSec = 0;
+ if (!connectionGapList.isEmpty()) {
+ satelliteConnectionGapMinSec = Collections.min(connectionGapList);
+ satelliteConnectionGapMaxSec = Collections.max(connectionGapList);
+ }
+
+ SatelliteStats.CarrierRoamingSatelliteSessionParams params =
+ new SatelliteStats.CarrierRoamingSatelliteSessionParams.Builder()
+ .setCarrierId(mCarrierId)
+ .setIsNtnRoamingInHomeCountry(mIsNtnRoamingInHomeCountry)
+ .setTotalSatelliteModeTimeSec(totalSatelliteModeTimeSec)
+ .setNumberOfSatelliteConnections(numberOfSatelliteConnections)
+ .setAvgDurationOfSatelliteConnectionSec(avgDurationOfSatelliteConnectionSec)
+ .setSatelliteConnectionGapMinSec(satelliteConnectionGapMinSec)
+ .setSatelliteConnectionGapAvgSec(getAvgConnectionGapSec(connectionGapList))
+ .setSatelliteConnectionGapMaxSec(satelliteConnectionGapMaxSec)
+ .setRsrpAvg(mRsrpAvg)
+ .setRsrpMedian(mRsrpMedian)
+ .setRssnrAvg(mRssnrAvg)
+ .setRssnrMedian(mRssnrMedian)
+ .setCountOfIncomingSms(mCountOfIncomingSms)
+ .setCountOfOutgoingSms(mCountOfOutgoingSms)
+ .setCountOfIncomingMms(mCountOfIncomingMms)
+ .setCountOfOutgoingMms(mCountOfOutgoingMms)
+ .build();
+ SatelliteStats.getInstance().onCarrierRoamingSatelliteSessionMetrics(params);
+ logd("reportMetrics: " + params);
+ initializeParams();
+ }
+
+ private void initializeParams() {
+ mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+ mIsNtnRoamingInHomeCountry = false;
+ mRsrpAvg = 0;
+ mRsrpMedian = 0;
+ mRssnrAvg = 0;
+ mRssnrMedian = 0;
+ mCountOfIncomingSms = 0;
+ mCountOfOutgoingSms = 0;
+ mCountOfIncomingMms = 0;
+ mCountOfOutgoingMms = 0;
+
+ mSessionStartTimeSec = 0;
+ mConnectionStartTimeList = new ArrayList<>();
+ mConnectionEndTimeList = new ArrayList<>();
+ }
+
+ private int getNumberOfSatelliteConnections() {
+ return Math.min(mConnectionStartTimeList.size(), mConnectionEndTimeList.size());
+ }
+
+ private int getAvgDurationOfSatelliteConnection(int numberOfSatelliteConnections) {
+ if (numberOfSatelliteConnections == 0) {
+ return 0;
+ }
+
+ long totalConnectionsDuration = 0;
+ for (int i = 0; i < numberOfSatelliteConnections; i++) {
+ long endTime = mConnectionEndTimeList.get(i);
+ long startTime = mConnectionStartTimeList.get(i);
+ if (endTime >= startTime && startTime > 0) {
+ totalConnectionsDuration += endTime - startTime;
+ }
+ }
+
+ long avgConnectionDuration = totalConnectionsDuration / numberOfSatelliteConnections;
+ return (int) (avgConnectionDuration / 1000L);
+ }
+
+ private List<Integer> getSatelliteConnectionGapList(int numberOfSatelliteConnections) {
+ if (numberOfSatelliteConnections == 0) {
+ return new ArrayList<>();
+ }
+
+ List<Integer> connectionGapList = new ArrayList<>();
+ for (int i = 1; i < numberOfSatelliteConnections; i++) {
+ long prevConnectionEndTime = mConnectionEndTimeList.get(i - 1);
+ long currentConnectionStartTime = mConnectionStartTimeList.get(i);
+ if (currentConnectionStartTime > prevConnectionEndTime && prevConnectionEndTime > 0) {
+ connectionGapList.add((int) (
+ (currentConnectionStartTime - prevConnectionEndTime) / 1000));
+ }
+ }
+ return connectionGapList;
+ }
+
+ private int getAvgConnectionGapSec(@NonNull List<Integer> connectionGapList) {
+ if (connectionGapList.isEmpty()) {
+ return 0;
+ }
+
+ int totalConnectionGap = 0;
+ for (int gap : connectionGapList) {
+ totalConnectionGap += gap;
+ }
+
+ return (totalConnectionGap / connectionGapList.size());
+ }
+
+ private int getCurrentTimeInSec() {
+ return (int) (System.currentTimeMillis() / 1000);
+ }
+
+ private long getCurrentTime() {
+ return System.currentTimeMillis();
+ }
+
+ private void logd(@NonNull String log) {
+ Log.d(TAG, log);
+ }
+
+ private void loge(@NonNull String log) {
+ Log.e(TAG, log);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ConfigUpdaterMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ConfigUpdaterMetricsStats.java
new file mode 100644
index 0000000..c379b83
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/metrics/ConfigUpdaterMetricsStats.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite.metrics;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import com.android.internal.telephony.metrics.SatelliteStats;
+import com.android.internal.telephony.satellite.SatelliteConstants;
+
+public class ConfigUpdaterMetricsStats {
+ private static final String TAG = ConfigUpdaterMetricsStats.class.getSimpleName();
+ private static ConfigUpdaterMetricsStats sInstance = null;
+
+ private int mConfigVersion;
+ private int mOemConfigResult;
+ private int mCarrierConfigResult;
+
+ private ConfigUpdaterMetricsStats() {
+ initializeConfigUpdaterParams();
+ }
+
+ /**
+ * Returns the Singleton instance of ConfigUpdaterMetricsStats class.
+ * If an instance of the Singleton class has not been created,
+ * it creates a new instance and returns it. Otherwise, it returns
+ * the existing instance.
+ * @return the Singleton instance of ConfigUpdaterMetricsStats
+ */
+ public static ConfigUpdaterMetricsStats getOrCreateInstance() {
+ if (sInstance == null) {
+ logd("Create new ConfigUpdaterMetricsStats.");
+ sInstance = new ConfigUpdaterMetricsStats();
+ }
+ return sInstance;
+ }
+
+ /** Set config version for config updater metrics */
+ public ConfigUpdaterMetricsStats setConfigVersion(int configVersion) {
+ mConfigVersion = configVersion;
+ return this;
+ }
+
+ /** Set oem config result for config updater metrics */
+ public ConfigUpdaterMetricsStats setOemConfigResult(int oemConfigResult) {
+ mOemConfigResult = oemConfigResult;
+ return this;
+ }
+
+ /** Set carrier config result for config updater metrics */
+ public ConfigUpdaterMetricsStats setCarrierConfigResult(int carrierConfigResult) {
+ mCarrierConfigResult = carrierConfigResult;
+ return this;
+ }
+
+ /** Report metrics on oem config update error */
+ public void reportOemConfigError(int error) {
+ mOemConfigResult = error;
+ reportConfigUpdaterMetrics();
+ }
+
+ /** Report metrics on carrier config update error */
+ public void reportCarrierConfigError(int error) {
+ mCarrierConfigResult = error;
+ reportConfigUpdaterMetrics();
+ }
+
+ /** Report metrics on config update error */
+ public void reportOemAndCarrierConfigError(int error) {
+ mOemConfigResult = error;
+ mCarrierConfigResult = error;
+ reportConfigUpdaterMetrics();
+ }
+
+ /** Report metrics on config update success */
+ public void reportConfigUpdateSuccess() {
+ mOemConfigResult = SatelliteConstants.CONFIG_UPDATE_RESULT_SUCCESS;
+ mCarrierConfigResult = SatelliteConstants.CONFIG_UPDATE_RESULT_SUCCESS;
+ reportConfigUpdaterMetrics();
+ }
+
+
+ /** Report config updater metrics atom to PersistAtomsStorage in telephony */
+ private void reportConfigUpdaterMetrics() {
+ SatelliteStats.SatelliteConfigUpdaterParams configUpdaterParams =
+ new SatelliteStats.SatelliteConfigUpdaterParams.Builder()
+ .setConfigVersion(mConfigVersion)
+ .setOemConfigResult(mOemConfigResult)
+ .setCarrierConfigResult(mCarrierConfigResult)
+ .setCount(1)
+ .build();
+ SatelliteStats.getInstance().onSatelliteConfigUpdaterMetrics(configUpdaterParams);
+ logd("reportConfigUpdaterMetrics: " + configUpdaterParams);
+
+ CarrierRoamingSatelliteControllerStats.getOrCreateInstance()
+ .reportCountOfSatelliteConfigUpdateRequest();
+
+ initializeConfigUpdaterParams();
+ }
+
+ private void initializeConfigUpdaterParams() {
+ mConfigVersion = -1;
+ mOemConfigResult = SatelliteConstants.CONFIG_UPDATE_RESULT_UNKNOWN;
+ mCarrierConfigResult = SatelliteConstants.CONFIG_UPDATE_RESULT_UNKNOWN;
+ }
+
+ private static void logd(@NonNull String log) {
+ Log.d(TAG, log);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/metrics/EntitlementMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/EntitlementMetricsStats.java
new file mode 100644
index 0000000..4862188
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/metrics/EntitlementMetricsStats.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite.metrics;
+
+import android.annotation.NonNull;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.metrics.SatelliteStats;
+import com.android.internal.telephony.satellite.SatelliteConstants;
+
+public class EntitlementMetricsStats {
+ private static final String TAG = EntitlementMetricsStats.class.getSimpleName();
+ private static EntitlementMetricsStats sInstance = null;
+ private static final int RESULT_SUCCESS = 200;
+
+ private int mSubId;
+ private int mResult;
+ private int mEntitlementStatus;
+ private boolean mIsRetry;
+
+ private EntitlementMetricsStats() {}
+
+ /**
+ * Returns the Singleton instance of EntitlementMetricsStats class.
+ * If an instance of the Singleton class has not been created,
+ * it creates a new instance and returns it. Otherwise, it returns
+ * the existing instance.
+ * @return the Singleton instance of EntitlementMetricsStats
+ */
+ public static EntitlementMetricsStats getOrCreateInstance() {
+ if (sInstance == null) {
+ logd("Create new EntitlementMetricsStats.");
+ sInstance = new EntitlementMetricsStats();
+ }
+ return sInstance;
+ }
+
+ /** Report metrics on entitlement query request success */
+ public void reportSuccess(int subId,
+ @SatelliteConstants.SatelliteEntitlementStatus int entitlementStatus,
+ boolean isRetry) {
+ mSubId = subId;
+ mResult = RESULT_SUCCESS;
+ mEntitlementStatus = entitlementStatus;
+ mIsRetry = isRetry;
+ reportEntitlementMetrics();
+ }
+
+ /** Report metrics on entitlement query request error */
+ public void reportError(int subId, int result, boolean isRetry) {
+ mSubId = subId;
+ mResult = result;
+ mIsRetry = isRetry;
+ mEntitlementStatus = SatelliteConstants.SATELLITE_ENTITLEMENT_STATUS_UNKNOWN;
+ reportEntitlementMetrics();
+ }
+
+ /** Report entitlement metrics atom to PersistAtomsStorage in telephony */
+ private void reportEntitlementMetrics() {
+ SatelliteStats.SatelliteEntitlementParams entitlementParams =
+ new SatelliteStats.SatelliteEntitlementParams.Builder()
+ .setCarrierId(getCarrierId(mSubId))
+ .setResult(mResult)
+ .setEntitlementStatus(mEntitlementStatus)
+ .setIsRetry(mIsRetry)
+ .setCount(1)
+ .build();
+ SatelliteStats.getInstance().onSatelliteEntitlementMetrics(entitlementParams);
+ logd("reportEntitlementMetrics: " + entitlementParams);
+
+ CarrierRoamingSatelliteControllerStats.getOrCreateInstance()
+ .reportCountOfEntitlementStatusQueryRequest();
+ }
+
+ /** Returns the carrier ID of the given subscription id. */
+ private int getCarrierId(int subId) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ Phone phone = PhoneFactory.getPhone(phoneId);
+ return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID;
+ }
+
+ private static void logd(@NonNull String log) {
+ Log.d(TAG, log);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java b/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
index 34f26e3..2d4776c 100644
--- a/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
+++ b/src/java/com/android/internal/telephony/security/CellularNetworkSecuritySafetySource.java
@@ -25,11 +25,14 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
import android.safetycenter.SafetySourceStatus;
+import android.text.format.DateFormat;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -39,8 +42,10 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;
-import java.util.Date;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
@@ -62,10 +67,6 @@
private static final Intent CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT =
new Intent("android.settings.CELLULAR_NETWORK_SECURITY");
- // TODO(b/321999913): direct to a help page URL e.g.
- // new Intent(Intent.ACTION_VIEW, Uri.parse("https://..."));
- private static final Intent LEARN_MORE_INTENT = new Intent();
-
static final int NULL_CIPHER_STATE_ENCRYPTED = 0;
static final int NULL_CIPHER_STATE_NOTIFY_ENCRYPTED = 1;
static final int NULL_CIPHER_STATE_NOTIFY_NON_ENCRYPTED = 2;
@@ -123,6 +124,13 @@
}
/**
+ * Clears issue state for the identified subscription
+ */
+ public synchronized void clearNullCipherState(Context context, int subId) {
+ mNullCipherStates.remove(subId);
+ updateSafetyCenter(context);
+ }
+ /**
* Enables or disables the identifier disclosure issue and clears any current issues if the
* enable state is changed.
*/
@@ -209,6 +217,7 @@
SubscriptionInfoInternal subInfo =
mSubscriptionManagerService.getSubscriptionInfoInternal(subId);
final SafetySourceIssue.Builder builder;
+ final SafetySourceIssue.Notification customNotification;
switch (state) {
case NULL_CIPHER_STATE_ENCRYPTED:
return Optional.empty();
@@ -216,43 +225,70 @@
builder = new SafetySourceIssue.Builder(
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID + "_" + subId,
context.getString(
- R.string.scNullCipherIssueNonEncryptedTitle, subInfo.getDisplayName()),
- context.getString(R.string.scNullCipherIssueNonEncryptedSummary),
+ R.string.scNullCipherIssueNonEncryptedTitle),
+ context.getString(
+ R.string.scNullCipherIssueNonEncryptedSummary,
+ subInfo.getDisplayName()),
SEVERITY_LEVEL_RECOMMENDATION,
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID);
+ customNotification =
+ new SafetySourceIssue.Notification.Builder(
+ context.getString(R.string.scNullCipherIssueNonEncryptedTitle),
+ context.getString(
+ R.string.scNullCipherIssueNonEncryptedSummaryNotification,
+ subInfo.getDisplayName()))
+ .build();
break;
case NULL_CIPHER_STATE_NOTIFY_ENCRYPTED:
builder = new SafetySourceIssue.Builder(
NULL_CIPHER_ISSUE_NON_ENCRYPTED_ID + "_" + subId,
context.getString(
- R.string.scNullCipherIssueEncryptedTitle, subInfo.getDisplayName()),
- context.getString(R.string.scNullCipherIssueEncryptedSummary),
+ R.string.scNullCipherIssueEncryptedTitle,
+ subInfo.getDisplayName()),
+ context.getString(
+ R.string.scNullCipherIssueEncryptedSummary,
+ subInfo.getDisplayName()),
SEVERITY_LEVEL_INFORMATION,
NULL_CIPHER_ISSUE_ENCRYPTED_ID);
+ customNotification =
+ new SafetySourceIssue.Notification.Builder(
+ context.getString(
+ R.string.scNullCipherIssueEncryptedTitle,
+ subInfo.getDisplayName()),
+ context.getString(
+ R.string.scNullCipherIssueEncryptedSummary,
+ subInfo.getDisplayName()))
+ .build();
break;
default:
throw new AssertionError();
}
-
- return Optional.of(
- builder
- .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
- .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
- .addAction(
+ builder
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .setCustomNotification(customNotification)
+ .addAction(
new SafetySourceIssue.Action.Builder(
NULL_CIPHER_ACTION_SETTINGS_ID,
context.getString(R.string.scNullCipherIssueActionSettings),
mSafetyCenterManagerWrapper.getActivityPendingIntent(
context, CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
- .build())
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_LEARN_MORE_ID,
- context.getString(R.string.scNullCipherIssueActionLearnMore),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, LEARN_MORE_INTENT))
- .build())
- .build());
+ .build());
+
+ Intent learnMoreIntent = getLearnMoreIntent(context);
+ if (learnMoreIntent != null) {
+ builder.addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_LEARN_MORE_ID,
+ context.getString(
+ R.string.scNullCipherIssueActionLearnMore),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context, learnMoreIntent))
+ .build());
+ }
+
+ return Optional.of(builder.build());
}
/** Builds the identity disclosure issue if it's enabled and there are disclosures to report. */
@@ -264,35 +300,77 @@
SubscriptionInfoInternal subInfo =
mSubscriptionManagerService.getSubscriptionInfoInternal(subId);
- return Optional.of(
+
+ // Notifications have no buttons
+ final SafetySourceIssue.Notification customNotification =
+ new SafetySourceIssue.Notification.Builder(
+ context.getString(R.string.scIdentifierDisclosureIssueTitle),
+ context.getString(
+ R.string.scIdentifierDisclosureIssueSummaryNotification,
+ getCurrentTime(),
+ subInfo.getDisplayName())).build();
+ SafetySourceIssue.Builder builder =
new SafetySourceIssue.Builder(
IDENTIFIER_DISCLOSURE_ISSUE_ID + "_" + subId,
context.getString(R.string.scIdentifierDisclosureIssueTitle),
context.getString(
R.string.scIdentifierDisclosureIssueSummary,
- disclosure.getDisclosureCount(),
- Date.from(disclosure.getWindowStart()),
- Date.from(disclosure.getWindowEnd()),
+ getCurrentTime(),
subInfo.getDisplayName()),
SEVERITY_LEVEL_RECOMMENDATION,
IDENTIFIER_DISCLOSURE_ISSUE_ID)
- .setNotificationBehavior(SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
- .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_SETTINGS_ID,
- context.getString(R.string.scNullCipherIssueActionSettings),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
- .build())
- .addAction(
- new SafetySourceIssue.Action.Builder(
- NULL_CIPHER_ACTION_LEARN_MORE_ID,
- context.getString(R.string.scNullCipherIssueActionLearnMore),
- mSafetyCenterManagerWrapper.getActivityPendingIntent(
- context, LEARN_MORE_INTENT))
- .build())
- .build());
+ .setNotificationBehavior(
+ SafetySourceIssue.NOTIFICATION_BEHAVIOR_IMMEDIATELY)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DATA)
+ .setCustomNotification(customNotification)
+ .addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_SETTINGS_ID,
+ context.getString(
+ R.string.scNullCipherIssueActionSettings),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context,
+ CELLULAR_NETWORK_SECURITY_SETTINGS_INTENT))
+ .build());
+
+ Intent learnMoreIntent = getLearnMoreIntent(context);
+ if (learnMoreIntent != null) {
+ builder.addAction(
+ new SafetySourceIssue.Action.Builder(
+ NULL_CIPHER_ACTION_LEARN_MORE_ID,
+ context.getString(R.string.scNullCipherIssueActionLearnMore),
+ mSafetyCenterManagerWrapper.getActivityPendingIntent(
+ context, learnMoreIntent)).build()
+ );
+ }
+
+ return Optional.of(builder.build());
+ }
+
+ private String getCurrentTime() {
+ String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "hh:mm");
+ return Instant.now().atZone(ZoneId.systemDefault())
+ .format(DateTimeFormatter.ofPattern(pattern)).toString();
+ }
+
+ /**
+ * Return Intent for learn more action, or null if resource associated with the Intent
+ * uri is
+ * missing or empty.
+ */
+ private Intent getLearnMoreIntent(Context context) {
+ String learnMoreUri;
+ try {
+ learnMoreUri = context.getString(R.string.scCellularNetworkSecurityLearnMore);
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+
+ if (learnMoreUri.isEmpty()) {
+ return null;
+ }
+
+ return new Intent(Intent.ACTION_VIEW, Uri.parse(learnMoreUri));
}
/** A wrapper around {@link SafetyCenterManager} that can be instrumented in tests. */
@@ -337,7 +415,7 @@
private IdentifierDisclosure(int count, Instant start, Instant end) {
mDisclosureCount = count;
mWindowStart = start;
- mWindowEnd = end;
+ mWindowEnd = end;
}
private int getDisclosureCount() {
diff --git a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
index 3ece701..e13c5b0 100644
--- a/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
+++ b/src/java/com/android/internal/telephony/security/NullCipherNotifier.java
@@ -56,6 +56,7 @@
private final CellularNetworkSecuritySafetySource mSafetySource;
private final HashMap<Integer, SubscriptionState> mSubscriptionState = new HashMap<>();
+ private final HashMap<Integer, Integer> mActiveSubscriptions = new HashMap<>();
private final Object mEnabledLock = new Object();
@GuardedBy("mEnabledLock")
@@ -90,31 +91,78 @@
* Adds a security algorithm update. If appropriate, this will trigger a user notification.
*/
public void onSecurityAlgorithmUpdate(
- Context context, int subId, SecurityAlgorithmUpdate update) {
+ Context context, int phoneId, int subId, SecurityAlgorithmUpdate update) {
Rlog.d(TAG, "Security algorithm update: subId = " + subId + " " + update);
if (shouldIgnoreUpdate(update)) {
return;
}
+ if (!isEnabled()) {
+ Rlog.i(TAG, "Ignoring onSecurityAlgorithmUpdate. Notifier is disabled.");
+ return;
+ }
+
try {
mSerializedWorkQueue.execute(() -> {
- SubscriptionState subState = mSubscriptionState.get(subId);
- if (subState == null) {
- subState = new SubscriptionState();
- mSubscriptionState.put(subId, subState);
- }
+ try {
+ maybeUpdateSubscriptionMapping(context, phoneId, subId);
+ SubscriptionState subState = mSubscriptionState.get(subId);
+ if (subState == null) {
+ subState = new SubscriptionState();
+ mSubscriptionState.put(subId, subState);
+ }
- @CellularNetworkSecuritySafetySource.NullCipherState int nullCipherState =
- subState.update(update);
- mSafetySource.setNullCipherState(context, subId, nullCipherState);
+ @CellularNetworkSecuritySafetySource.NullCipherState int nullCipherState =
+ subState.update(update);
+ mSafetySource.setNullCipherState(context, subId, nullCipherState);
+ } catch (Throwable t) {
+ Rlog.e(TAG, "Failed to execute onSecurityAlgorithmUpdate " + t.getMessage());
+ }
});
} catch (RejectedExecutionException e) {
- Rlog.e(TAG, "Failed to schedule onEnableNotifier: " + e.getMessage());
+ Rlog.e(TAG, "Failed to schedule onSecurityAlgorithmUpdate: " + e.getMessage());
}
}
/**
+ * Set or update the current phoneId to subId mapping. When a new subId is mapped to a phoneId,
+ * we update the safety source to clear state of the old subId.
+ */
+ public void setSubscriptionMapping(Context context, int phoneId, int subId) {
+
+ if (!isEnabled()) {
+ Rlog.i(TAG, "Ignoring setSubscriptionMapping. Notifier is disabled.");
+ }
+
+ try {
+ mSerializedWorkQueue.execute(() -> {
+ try {
+ maybeUpdateSubscriptionMapping(context, phoneId, subId);
+ } catch (Throwable t) {
+ Rlog.e(TAG, "Failed to update subId mapping. phoneId: " + phoneId + " subId: "
+ + subId + ". " + t.getMessage());
+ }
+ });
+
+ } catch (RejectedExecutionException e) {
+ Rlog.e(TAG, "Failed to schedule setSubscriptionMapping: " + e.getMessage());
+ }
+ }
+
+ private void maybeUpdateSubscriptionMapping(Context context, int phoneId, int subId) {
+ final Integer oldSubId = mActiveSubscriptions.put(phoneId, subId);
+ if (oldSubId == null || oldSubId == subId) {
+ return;
+ }
+
+ // Our subId was updated for this phone, we should clear this subId's state.
+ mSubscriptionState.remove(oldSubId);
+ mSafetySource.clearNullCipherState(context, oldSubId);
+ }
+
+
+ /**
* Enables null cipher notification; {@code onSecurityAlgorithmUpdate} will start handling
* security algorithm updates and send notifications to the user when required.
*/
@@ -285,7 +333,7 @@
/** The state of security algorithms for a network connection. */
private static final class ConnectionState {
private static final ConnectionState UNKNOWN =
- new ConnectionState(SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_UNKNOWN);
+ new ConnectionState(SECURITY_ALGORITHM_UNKNOWN, SECURITY_ALGORITHM_UNKNOWN);
private final @SecurityAlgorithm int mEncryption;
private final @SecurityAlgorithm int mIntegrity;
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 2e0bd31..5d653c7 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -318,6 +318,9 @@
@NonNull
private final int[] mSimState;
+ /** Vendor API level from system property. */
+ private final int mVendorApiLevel;
+
/**
* {@code true} if a user profile can only see the SIMs associated with it, unless it possesses
* no SIMs on the device.
@@ -472,6 +475,8 @@
mEuiccManager = context.getSystemService(EuiccManager.class);
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mPackageManager = context.getPackageManager();
+ mVendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
mUiccController = UiccController.getInstance();
mHandler = new Handler(looper);
@@ -938,9 +943,13 @@
*
* @param subId Subscription id.
* @param groupOwner The group owner to assign to the subscription
+ *
+ * @throws SecurityException if the caller does not have required permissions.
*/
+ @Override
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setGroupOwner(int subId, @NonNull String groupOwner) {
- // This can throw IllegalArgumentException if the subscription does not exist.
+ enforcePermissions("setGroupOwner", Manifest.permission.MODIFY_PHONE_STATE);
try {
mSubscriptionDatabaseManager.setGroupOwner(
subId,
@@ -1578,6 +1587,10 @@
SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED)) {
logl("Sim specific settings changed the database.");
mSubscriptionDatabaseManager.reloadDatabaseSync();
+ if (mFeatureFlags.backupAndRestoreForEnable2g()) {
+ PhoneFactory.getPhone(phoneId)
+ .loadAllowedNetworksFromSubscriptionDatabase();
+ }
}
}
@@ -3762,42 +3775,114 @@
"carrier privileges",
})
public String getPhoneNumber(int subId, @PhoneNumberSource int source,
- @NonNull String callingPackage, @Nullable String callingFeatureId) {
+ @NonNull String callingPackage, @Nullable String callingFeatureId /* unused */) {
TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges(
mContext, subId, Binder.getCallingUid(), "getPhoneNumber",
Manifest.permission.READ_PHONE_NUMBERS,
Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
-
enforceTelephonyFeatureWithException(callingPackage, "getPhoneNumber");
- final long identity = Binder.clearCallingIdentity();
+ if (mFeatureFlags.saferGetPhoneNumber()) {
+ checkPhoneNumberSource(source);
+ subId = checkAndGetSubId(subId);
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return "";
- SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return getPhoneNumberFromSourceInternal(subId, source);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
+ .getSubscriptionInfoInternal(subId);
+
+ if (subInfo == null) {
+ loge("Invalid sub id " + subId + ", callingPackage=" + callingPackage);
+ return "";
+ }
+
+ switch(source) {
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC:
+ Phone phone = PhoneFactory.getPhone(getSlotIndex(subId));
+ if (phone != null) {
+ return TextUtils.emptyIfNull(phone.getLine1Number());
+ } else {
+ return subInfo.getNumber();
+ }
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER:
+ return subInfo.getNumberFromCarrier();
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS:
+ return subInfo.getNumberFromIms();
+ default:
+ throw new IllegalArgumentException("Invalid number source " + source);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ /**
+ * Get a resolved subId based on what the user passed in.
+ *
+ * Only use this before clearing the calling binder. Used for compatibility (only).
+ * Do not use this behavior for new methods.
+ *
+ * @param subId the subId passed in by the user.
+ */
+ private int checkAndGetSubId(int subId) {
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ // for historical reasons, INVALID_SUB_ID fails gracefully
+ return subId;
+ } else if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+ return getDefaultSubId();
+ } else if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid SubId=" + subId);
+ } else {
+ return subId;
+ }
+ }
+
+ private void checkPhoneNumberSource(int source) {
+ if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_UICC
+ || source == SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER
+ || source == SubscriptionManager.PHONE_NUMBER_SOURCE_IMS) {
+ return;
+ }
+
+ throw new IllegalArgumentException("Invalid number source " + source);
+ }
+
+ private @NonNull String getPhoneNumberFromSourceInternal(
+ int subId,
+ @PhoneNumberSource int source) {
+
+ final SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager
.getSubscriptionInfoInternal(subId);
if (subInfo == null) {
- loge("Invalid sub id " + subId + ", callingPackage=" + callingPackage);
+ loge("No SubscriptionInfo found for subId=" + subId);
return "";
}
- try {
- switch(source) {
- case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC:
- Phone phone = PhoneFactory.getPhone(getSlotIndex(subId));
- if (phone != null) {
- return TextUtils.emptyIfNull(phone.getLine1Number());
- } else {
- return subInfo.getNumber();
- }
- case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER:
- return subInfo.getNumberFromCarrier();
- case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS:
- return subInfo.getNumberFromIms();
- default:
- throw new IllegalArgumentException("Invalid number source " + source);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ switch(source) {
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC:
+ final Phone phone = PhoneFactory.getPhone(getSlotIndex(subId));
+ if (phone != null) {
+ return TextUtils.emptyIfNull(phone.getLine1Number());
+ } else {
+ return subInfo.getNumber();
+ }
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER:
+ return subInfo.getNumberFromCarrier();
+ case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS:
+ return subInfo.getNumberFromIms();
+ default:
+ loge("No SubscriptionInfo found for subId=" + subId);
+ return "";
}
}
@@ -3833,25 +3918,51 @@
enforceTelephonyFeatureWithException(callingPackage,
"getPhoneNumberFromFirstAvailableSource");
- String numberFromCarrier = getPhoneNumber(subId,
- SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, callingPackage,
- callingFeatureId);
- if (!TextUtils.isEmpty(numberFromCarrier)) {
- return numberFromCarrier;
+ if (mFeatureFlags.saferGetPhoneNumber()) {
+ subId = checkAndGetSubId(subId);
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return "";
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ String number;
+ number = getPhoneNumberFromSourceInternal(
+ subId,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER);
+ if (!TextUtils.isEmpty(number)) return number;
+
+ number = getPhoneNumberFromSourceInternal(
+ subId,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_UICC);
+ if (!TextUtils.isEmpty(number)) return number;
+
+ number = getPhoneNumberFromSourceInternal(
+ subId,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_IMS);
+ return TextUtils.emptyIfNull(number);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else {
+ String numberFromCarrier = getPhoneNumber(subId,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, callingPackage,
+ callingFeatureId);
+ if (!TextUtils.isEmpty(numberFromCarrier)) {
+ return numberFromCarrier;
+ }
+ String numberFromUicc = getPhoneNumber(
+ subId, SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, callingPackage,
+ callingFeatureId);
+ if (!TextUtils.isEmpty(numberFromUicc)) {
+ return numberFromUicc;
+ }
+ String numberFromIms = getPhoneNumber(
+ subId, SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, callingPackage,
+ callingFeatureId);
+ if (!TextUtils.isEmpty(numberFromIms)) {
+ return numberFromIms;
+ }
+ return "";
}
- String numberFromUicc = getPhoneNumber(
- subId, SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, callingPackage,
- callingFeatureId);
- if (!TextUtils.isEmpty(numberFromUicc)) {
- return numberFromUicc;
- }
- String numberFromIms = getPhoneNumber(
- subId, SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, callingPackage,
- callingFeatureId);
- if (!TextUtils.isEmpty(numberFromIms)) {
- return numberFromIms;
- }
- return "";
}
/**
@@ -4199,6 +4310,10 @@
SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_DATABASE_UPDATED)) {
logl("Sim specific settings changed the database.");
mSubscriptionDatabaseManager.reloadDatabaseSync();
+ if (mFeatureFlags.backupAndRestoreForEnable2g()) {
+ Arrays.stream(PhoneFactory.getPhones())
+ .forEach(Phone::loadAllowedNetworksFromSubscriptionDatabase);
+ }
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -4532,7 +4647,11 @@
if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
|| !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
- Binder.getCallingUserHandle())) {
+ Binder.getCallingUserHandle())
+ || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ // Skip to check associated telephony feature,
+ // if compatibility change is not enabled for the current process or
+ // the SDK version of vendor partition is less than Android V.
return;
}
@@ -4605,6 +4724,11 @@
"config_satellite_sim_spn_identifier", "");
}
log("isSatelliteSpn: overlaySpn=" + overlaySpn + ", spn=" + spn);
+
+ if (TextUtils.isEmpty(spn) || TextUtils.isEmpty(overlaySpn)) {
+ return false;
+ }
+
return TextUtils.equals(spn, overlaySpn);
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 0459bf6..84e84d9 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -1799,6 +1799,8 @@
}
pw.decreaseIndent();
pw.println();
+ mCarrierServiceBindHelper.dump(fd, pw, args);
+ pw.println();
pw.println("sLocalLog= ");
pw.increaseIndent();
mPinStorage.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccPort.java b/src/java/com/android/internal/telephony/uicc/UiccPort.java
index fd8f1c4..9e341ef 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccPort.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java
@@ -31,6 +31,7 @@
import com.android.internal.telephony.TelephonyComponentFactory;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.flags.FeatureFlagsImpl;
+import com.android.internal.telephony.flags.Flags;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -57,8 +58,9 @@
private int mPortIdx;
private int mPhysicalSlotIndex;
- // The list of the opened logical channel record. The channels will be closed by us when
- // detecting client died without closing them in advance.
+ // The list of the opened logical channel record.
+ // The channels will be closed by us when detecting client died without closing them in advance.
+ // The same lock should be used to protect both access of the list and the individual record.
@GuardedBy("mOpenChannelRecords")
private final List<OpenLogicalChannelRecord> mOpenChannelRecords = new ArrayList<>();
@@ -101,11 +103,13 @@
}
mUiccProfile = null;
}
+ cleanupOpenLogicalChannelRecordsIfNeeded();
}
@Override
protected void finalize() {
if (DBG) log("UiccPort finalized");
+ cleanupOpenLogicalChannelRecordsIfNeeded();
}
/**
@@ -389,8 +393,10 @@
public void onLogicalChannelOpened(@NonNull IccLogicalChannelRequest request) {
OpenLogicalChannelRecord record = new OpenLogicalChannelRecord(request);
try {
- request.binder.linkToDeath(record, /*flags=*/ 0);
- addOpenLogicalChannelRecord(record);
+ synchronized (mOpenChannelRecords) {
+ request.binder.linkToDeath(record, /*flags=*/ 0);
+ mOpenChannelRecords.add(record);
+ }
if (DBG) log("onLogicalChannelOpened: monitoring client " + record);
} catch (RemoteException | NullPointerException ex) {
loge("IccOpenLogicChannel client has died, clean up manually");
@@ -406,11 +412,13 @@
*/
public void onLogicalChannelClosed(int channelId) {
OpenLogicalChannelRecord record = getOpenLogicalChannelRecord(channelId);
- if (record != null && record.mRequest != null && record.mRequest.binder != null) {
- if (DBG) log("onLogicalChannelClosed: stop monitoring client " + record);
- record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0);
- removeOpenLogicalChannelRecord(record);
- record.mRequest.binder = null;
+ synchronized (mOpenChannelRecords) {
+ if (record != null && record.mRequest != null && record.mRequest.binder != null) {
+ if (DBG) log("onLogicalChannelClosed: stop monitoring client " + record);
+ record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0);
+ record.mRequest.binder = null;
+ mOpenChannelRecords.remove(record);
+ }
}
}
@@ -428,15 +436,21 @@
return null;
}
- private void addOpenLogicalChannelRecord(OpenLogicalChannelRecord record) {
- synchronized (mOpenChannelRecords) {
- mOpenChannelRecords.add(record);
- }
- }
-
- private void removeOpenLogicalChannelRecord(OpenLogicalChannelRecord record) {
- synchronized (mOpenChannelRecords) {
- mOpenChannelRecords.remove(record);
+ /**
+ * Clean up records when logical channels underneath have been released, in cases like SIM
+ * removal or modem reset. The obsoleted records may trigger a redundant release of logical
+ * channel that may have been assigned to other client.
+ */
+ private void cleanupOpenLogicalChannelRecordsIfNeeded() {
+ if (Flags.cleanupOpenLogicalChannelRecordOnDispose()) {
+ synchronized (mOpenChannelRecords) {
+ for (OpenLogicalChannelRecord record : mOpenChannelRecords) {
+ if (DBG) log("Clean up " + record);
+ record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0);
+ record.mRequest.binder = null;
+ }
+ mOpenChannelRecords.clear();
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 0457971..a22f075 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -1290,6 +1290,11 @@
return -1;
}
+ if (mUiccApplications[index] == null) {
+ loge("App index " + index + " is invalid");
+ return -1;
+ }
+
if (mUiccApplications[index].getType() != expectedAppType
&& mUiccApplications[index].getType() != altExpectedAppType) {
loge("App index " + index + " is invalid since it's not "
diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp
index 8547581..a6b47cd 100644
--- a/tests/telephonytests/Android.bp
+++ b/tests/telephonytests/Android.bp
@@ -1,4 +1,5 @@
package {
+ default_team: "trendy_team_fwk_telephony",
// See: http://go/android-license-faq
default_applicable_licenses: [
"frameworks_opt_telephony_tests_telephonytests_license",
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
index 07482e0..e60e95b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.times;
@@ -31,6 +32,8 @@
import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.Network;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
@@ -38,18 +41,18 @@
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.text.TextUtils;
import android.util.Pair;
import androidx.test.filters.SmallTest;
-import com.android.internal.telephony.flags.FeatureFlags;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
import org.mockito.Mockito;
import java.security.PublicKey;
@@ -91,7 +94,7 @@
+ "\"public-key\": \"" + CERT + "\"}]}";
private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
- private FeatureFlags mFeatureFlags;
+
@Before
public void setUp() throws Exception {
logd("CarrierActionAgentTest +Setup!");
@@ -99,15 +102,18 @@
mBundle = mContextFixture.getCarrierConfigBundle();
when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
when(mUserManager.isUserUnlocked()).thenReturn(true);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(false);
// Capture listener to emulate the carrier config change notification used later
ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
- mFeatureFlags = Mockito.mock(FeatureFlags.class);
- mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone, mFeatureFlags);
+ mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone);
verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
listenerArgumentCaptor.capture());
mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
-
+ mConnectivityManager = (ConnectivityManager) mPhone.getContext().getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ Network network = Mockito.mock(Network.class);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(network);
processAllMessages();
logd("CarrierActionAgentTest -Setup!");
}
@@ -331,8 +337,8 @@
expectedCal.add(Calendar.DATE, 1);
String dateExpected = dt.format(expectedCal.getTime());
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
Intent mIntent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
mIntent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
mContext.sendBroadcast(mIntent);
@@ -355,11 +361,11 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
assertEquals(1, mCarrierKeyDM.mCarrierId);
@@ -369,6 +375,7 @@
@SmallTest
public void testCarrierConfigChangedWithUserLocked() {
when(mUserManager.isUserUnlocked()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int slotId = mPhone.getPhoneId();
@@ -376,14 +383,14 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
- assertNull(mCarrierKeyDM.mMccMncForDownload);
- assertEquals(0, mCarrierKeyDM.mCarrierId);
+ assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
+ assertEquals(1, mCarrierKeyDM.mCarrierId);
}
@Test
@@ -391,6 +398,7 @@
public void testUserLockedAfterCarrierConfigChanged() {
// User is locked at beginning
when(mUserManager.isUserUnlocked()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
int slotId = mPhone.getPhoneId();
@@ -399,17 +407,18 @@
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
// Carrier config change received
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
// User unlocked event received
- Intent mIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ Intent mIntent = new Intent(Intent.ACTION_USER_PRESENT);
mContext.sendBroadcast(mIntent);
when(mUserManager.isUserUnlocked()).thenReturn(true);
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(false);
processAllMessages();
assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
@@ -432,11 +441,11 @@
mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+ 1, TelephonyManager.UNKNOWN_CARRIER_ID);
processAllMessages();
- assertNull(mCarrierKeyDM.mMccMncForDownload);
+ assertTrue(TextUtils.isEmpty(mCarrierKeyDM.mMccMncForDownload));
- verify(mPhone).deleteCarrierInfoForImsiEncryption(0);
+ verify(mPhone).deleteCarrierInfoForImsiEncryption(1, "");
}
/**
@@ -453,8 +462,8 @@
bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
- when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
- when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+ when(mPhone.getOperatorNumeric()).thenReturn("310260");
+ when(mPhone.getCarrierId()).thenReturn(1);
Intent mIntent = new Intent("com.android.internal.telephony.carrier_key_download_alarm");
mIntent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotIndex);
mContext.sendBroadcast(mIntent);
@@ -493,4 +502,4 @@
assertEquals(CarrierKeyDownloadManager
.cleanCertString("Comments before" + CERT + "Comments after"), CERT);
}
-}
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index bef8944..552b5a7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -362,6 +362,8 @@
return Context.ALARM_SERVICE;
} else if (serviceClass == DevicePolicyManager.class) {
return Context.DEVICE_POLICY_SERVICE;
+ } else if (serviceClass == NotificationManager.class) {
+ return Context.NOTIFICATION_SERVICE;
}
return super.getSystemServiceName(serviceClass);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 614846b..ba08f8b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -3019,7 +3019,63 @@
processAllMessages();
verify(mNullCipherNotifier, times(1))
- .onSecurityAlgorithmUpdate(eq(mContext), eq(0), eq(update));
+ .onSecurityAlgorithmUpdate(eq(mContext), eq(0), eq(0), eq(update));
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_flagDisabled() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(false);
+ Phone phoneUT = makeNewPhoneUT();
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, never()).setSubscriptionMapping(any(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_activeSubscription() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(true);
+
+ int subId = 10;
+ SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal.Builder().setSimSlotIndex(
+ 0).setId(subId).build();
+ when(mSubscriptionManagerService.getSubscriptionInfoInternal(subId)).thenReturn(
+ subInfo);
+ doReturn(subId).when(mSubscriptionManagerService)
+ .getSubId(anyInt());
+ Phone phoneUT = makeNewPhoneUT();
+
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, times(1)).setSubscriptionMapping(eq(mContext), eq(0), eq(10));
+ }
+
+ @Test
+ public void testUpdateNullCipherNotifier_inactiveSubscription() {
+ when(mFeatureFlags.enableModemCipherTransparencyUnsolEvents()).thenReturn(true);
+ int subId = 1;
+ SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal.Builder().setSimSlotIndex(
+ -1).setId(subId).build();
+ when(mSubscriptionManagerService.getSubscriptionInfoInternal(subId)).thenReturn(
+ subInfo);
+ doReturn(subId).when(mSubscriptionManagerService)
+ .getSubId(anyInt());
+ Phone phoneUT = makeNewPhoneUT();
+
+ phoneUT.sendMessage(
+ mPhoneUT.obtainMessage(
+ Phone.EVENT_SUBSCRIPTIONS_CHANGED,
+ new AsyncResult(null, null, null)));
+ processAllMessages();
+
+ verify(mNullCipherNotifier, times(1)).setSubscriptionMapping(eq(mContext), eq(0), eq(-1));
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index d1ab64d..a6b2000 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -911,6 +911,28 @@
// This time user data should be disabled on phone1.
verify(mDataSettingsManagerMock2).setDataEnabled(
TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE);
+
+ // Remove and insert back SIM before it's loaded.
+ clearInvocations(mSubscriptionManagerService);
+ markSubscriptionInactive(1/*subid*/);
+ sendCarrierConfigChanged(0/*phoneid*/, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ verify(mSubscriptionManagerService).setDefaultDataSubId(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ // insert it back, but carrier config not loaded yet
+ clearInvocations(mSubscriptionManagerService);
+ setSimSlotIndex(1/*subid*/, 0/*phoneid*/);
+ mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
+ sendCarrierConfigChanged(0/*phoneid*/, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ verify(mSubscriptionManagerService, never()).setDefaultDataSubId(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ // carrier config loaded
+ clearInvocations(mContext);
+ sendCarrierConfigChanged(0/*phoneid*/, 1/*subid*/);
+ verify(mContext).sendBroadcast(any());
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
index 6743d1c..0e04aff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java
@@ -57,6 +57,7 @@
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -157,6 +158,7 @@
init(1);
assertEquals(PhoneCapability.DEFAULT_SSSS_CAPABILITY, mPcm.getStaticPhoneCapability());
+ mPcm.updateRadioCapability();
setAndVerifyStaticCapability(PhoneCapability.DEFAULT_DSDS_CAPABILITY);
}
@@ -171,6 +173,7 @@
.setMaxActiveVoiceSubscriptions(2)
.build();
+ mPcm.updateRadioCapability();
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).getPhoneCapability(captor.capture());
Message msg = captor.getValue();
@@ -188,7 +191,7 @@
init(2);
mPcm.updateSimultaneousCallingSupport();
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
Message msg = captor.getValue();
@@ -209,7 +212,7 @@
mPcm.updateSimultaneousCallingSupport();
// Have the modem send invalid phone slots -1 and 5:
- int[] invalidEnabledLogicalSlots = {-1, 5};
+ List<Integer> invalidEnabledLogicalSlots = Arrays.asList(-1, 5);
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
Message msg = captor.getValue();
@@ -245,14 +248,14 @@
mPcm.registerForSimultaneousCellularCallingSlotsChanged(newSlots ->
cachedSimultaneousCallingSlots[0] = newSlots);
- mPcm.getStaticPhoneCapability();
+ mPcm.updateRadioCapability();
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> cBCaptor =
ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
verify(mMockRegistryManager).addOnSubscriptionsChangedListener(cBCaptor.capture(), any());
processAllMessages();
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
HashSet<Integer> expectedSlots = new HashSet<>(2);
for (int i : enabledLogicalSlots) {
expectedSlots.add(i);
@@ -296,7 +299,7 @@
// Simultaneous calling enabled
mPcm.updateSimultaneousCallingSupport();
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
Message msg = captor.getValue();
@@ -318,7 +321,7 @@
// Simultaneous Calling Disabled
mPcm.updateSimultaneousCallingSupport();
- int[] disabled = {};
+ List<Integer> disabled = List.of();
captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig, times(2)).updateSimultaneousCallingSupport(captor.capture());
msg = captor.getAllValues().get(1);
@@ -346,13 +349,13 @@
// Set the capability to DSDA mode to register listener, which will also trigger
// simultaneous calling evaluation
- mPcm.getCurrentPhoneCapability();
+ mPcm.updateRadioCapability();
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> cBCaptor =
ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
verify(mMockRegistryManager).addOnSubscriptionsChangedListener(cBCaptor.capture(), any());
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
Message msg = captor.getValue();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 1c4e43d..bf9ced3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -21,7 +21,10 @@
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import com.android.internal.telephony.flags.Flags;
+
import android.net.Uri;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.PhoneNumberUtils;
import android.text.SpannableStringBuilder;
import android.text.style.TtsSpan;
@@ -32,6 +35,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
public class PhoneNumberUtilsTest {
@@ -40,6 +44,8 @@
private int mOldMinMatch;
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() throws Exception {
mOldMinMatch = PhoneNumberUtils.getMinMatchForTest();
@@ -613,6 +619,60 @@
assertEquals("+1 650-555-1212", PhoneNumberUtils.formatNumber("+16505551212", "jp"));
}
+ /**
+ * Test to ensure that when international calls to Singapore are being placed the country
+ * code is present with and without the feature flag enabled.
+ */
+ @SmallTest
+ @Test
+ public void testFormatSingaporeInternational() {
+ // Disable feature flag.
+ mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+
+ // International call from a US iso
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "US"));
+
+ // Lowercase country iso
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "us"));
+
+ // Enable feature flag
+ mSetFlagsRule.enableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+
+ // Internal call from a US iso
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "US"));
+
+ // Lowercase country iso
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "us"));
+ mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+ }
+
+ /**
+ * Test to ensure that when local calls from Singaporean numbers are being placed to other
+ * Singaporean numbers the country code +65 is not being shown.
+ */
+ @SmallTest
+ @Test
+ public void testFormatSingaporeNational() {
+ // Disable feature flag.
+ mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+
+ // Local call from a Singaporean number to a Singaporean number
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "SG"));
+
+ // Lowercase country iso.
+ assertEquals("+65 6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "sg"));
+
+ // Enable feature flag.
+ mSetFlagsRule.enableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+
+ // Local call from a Singaporean number to a Singaporean number.
+ assertEquals("6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "SG"));
+
+ // Lowercase country iso.
+ assertEquals("6521 8000", PhoneNumberUtils.formatNumber("+6565218000", "sg"));
+ mSetFlagsRule.disableFlags(Flags.FLAG_REMOVE_COUNTRY_CODE_FROM_LOCAL_SINGAPORE_CALLS);
+ }
+
@SmallTest
@Test
public void testFormatNumber_LeadingStarAndHash() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
index 1af4a76..d8005e8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java
@@ -43,7 +43,8 @@
import android.os.Build;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import com.android.internal.telephony.uicc.IsimUiccRecords;
import com.android.internal.telephony.uicc.SIMRecords;
@@ -230,7 +231,12 @@
@Test
@SmallTest
@EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
- public void testGetNai_EnabledEnforceTelephonyFeatureMappingForPublicApis() {
+ public void testGetNai_EnabledEnforceTelephonyFeatureMappingForPublicApis() throws Exception {
+ // Replace field to set SDK version of vendor partition to Android V
+ int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+ replaceInstance(PhoneSubInfoController.class, "mVendorApiLevel",
+ mPhoneSubInfoControllerUT, vendorApiLevel);
+
// FeatureFlags enabled, System has required feature
doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
doReturn(true).when(mPm).hasSystemFeature(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index bfe9649..88c5389 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -330,7 +330,7 @@
proxies.put(HAL_SERVICE_MODEM, mRadioModemProxy);
mRILInstance = new RIL(context,
RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE),
- Phone.PREFERRED_CDMA_SUBSCRIPTION, 0, proxies);
+ Phone.PREFERRED_CDMA_SUBSCRIPTION, 0, proxies, mFeatureFlags);
mRILUnderTest = spy(mRILInstance);
doReturn(mRadioProxy).when(mRILUnderTest).getRadioProxy();
doReturn(mDataProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioDataProxy.class));
@@ -354,6 +354,8 @@
replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV14);
} catch (Exception e) {
}
+
+ doReturn(true).when(mFeatureFlags).combineRilDeathHandle();
}
@After
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 121136d..fd99ad0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -2605,10 +2605,15 @@
waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
// PS WLAN
+ int wlanRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ if (wlanState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME
+ || wlanState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) {
+ wlanRat = TelephonyManager.NETWORK_TYPE_IWLAN;
+ }
NetworkRegistrationInfo dataIwlanResult = new NetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
- wlanState, TelephonyManager.NETWORK_TYPE_IWLAN, 0, false,
- null, null, "", 1, false, false, false, lteVopsSupportInfo);
+ wlanState, wlanRat, 0, false, null, null,
+ "", 1, false, false, false, lteVopsSupportInfo);
sst.sendMessage(sst.obtainMessage(
ServiceStateTracker.EVENT_POLL_STATE_PS_IWLAN_REGISTRATION,
new AsyncResult(sst.mPollingContext, dataIwlanResult, null)));
@@ -2645,6 +2650,47 @@
verify(mLocaleTracker).updateOperatorNumeric(eq(""));
}
+ /**
+ * Ensure that LocaleTracker is not updated with mcc when only IWLAN is not in-service and the
+ * ims registration status is connected over iwlan,
+ */
+ @Test
+ public void testLocaleTrackerUpdateWithImsRegistrationTechIwlan() {
+ // Start state: Cell data only LTE + IWLAN
+ final String[] OpNamesResult = new String[] { "carrier long", "carrier", "310310" };
+ // Clear invocations for mLocaleTracker as precondition before test case execution & as part
+ // test setup
+ Mockito.clearInvocations(mLocaleTracker);
+
+ // Both Cellular abd Iwlan is in-service.
+ changeRegStateWithIwlanOperatorNumeric(
+ NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ NetworkRegistrationInfo.REGISTRATION_STATE_HOME, OpNamesResult, true);
+ verify(mLocaleTracker).updateOperatorNumeric(eq(OpNamesResult[2]));
+
+ // Test with Cellular as NOT_REG
+ changeRegStateWithIwlanOperatorNumeric(
+ NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ NetworkRegistrationInfo.REGISTRATION_STATE_HOME, OpNamesResult, true);
+ /* cellId based mccmnc */
+ verify(mLocaleTracker).updateOperatorNumeric(eq("00101"));
+
+ // IMS over Iwlan is registered.
+ doReturn(mImsPhone)
+ .when(mPhone).getImsPhone();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
+ .when(mImsPhone).getImsRegistrationTech();
+
+ // Test with Iwlan as NOT_REG
+ changeRegStateWithIwlanOperatorNumeric(
+ NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
+ OpNamesResult, false);
+ verify(mLocaleTracker).updateOperatorNumeric(eq(""));
+ }
@Test
public void testGetServiceProviderNameWithBrandOverride() {
String brandOverride = "spn from brand override";
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
index d3fde34..879b184 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimultaneousCallingTrackerTest.java
@@ -172,7 +172,7 @@
}
private void setAndVerifyStaticCapability(PhoneCapability capability) {
- mPcm.getCurrentPhoneCapability();
+ mPcm.updateRadioCapability();
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).getPhoneCapability(captor.capture());
Message msg = captor.getValue();
@@ -185,7 +185,8 @@
}
- private void setAndVerifySlotsSupportingSimultaneousCellularCalling(int[] enabledLogicalSlots) {
+ private void setAndVerifySlotsSupportingSimultaneousCellularCalling(
+ List<Integer> enabledLogicalSlots) {
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
verify(mMockRadioConfig).updateSimultaneousCallingSupport(captor.capture());
Message msg = captor.getValue();
@@ -241,7 +242,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -264,7 +265,7 @@
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
// Have the modem inform telephony that only phone slot 0 supports DSDA:
- int[] enabledLogicalSlots = {0};
+ List<Integer> enabledLogicalSlots = List.of(0);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -286,7 +287,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -309,7 +310,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -356,7 +357,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -384,7 +385,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0};
+ List<Integer> enabledLogicalSlots = List.of(0);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -416,7 +417,7 @@
init(2);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
@@ -449,7 +450,7 @@
init(3);
setAndVerifyStaticCapability(STATIC_DSDA_CAPABILITY);
- int[] enabledLogicalSlots = {0, 1};
+ List<Integer> enabledLogicalSlots = Arrays.asList(0, 1);
setAndVerifySlotsSupportingSimultaneousCellularCalling(enabledLogicalSlots);
// Trigger onSubscriptionsChanged by updating the subscription ID of a phone slot:
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java
index f8d1bec..06dbd0b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java
@@ -31,6 +31,7 @@
import android.compat.testing.PlatformCompatChangeRule;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -295,11 +296,15 @@
@Test
@EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
- public void sendTextForSubscriberTestEnabledTelephonyFeature() {
+ public void sendTextForSubscriberTestEnabledTelephonyFeature() throws Exception {
int subId = 1;
doReturn(true).when(mSubscriptionManager)
.isSubscriptionAssociatedWithUser(eq(subId), any());
+ // Replace field to set SDK version of vendor partition to Android V
+ int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+ replaceInstance(SmsController.class, "mVendorApiLevel", mSmsControllerUT, vendorApiLevel);
+
// Feature enabled, device does not have required telephony feature.
doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
doReturn(false).when(mPackageManager).hasSystemFeature(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
index 6369825..d4717dd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
@@ -73,7 +73,6 @@
// Mocked classes
private Context mMockContext;
- private FeatureFlags mMockFeatureFlag;
private AppOpsManager mMockAppOps;
private SubscriptionManager mMockSubscriptionManager;
private ITelephony mMockTelephony;
@@ -92,7 +91,6 @@
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
- mMockFeatureFlag = mock(FeatureFlags.class);
mMockAppOps = mock(AppOpsManager.class);
mMockSubscriptionManager = mock(SubscriptionManager.class);
mMockTelephony = mock(ITelephony.class);
@@ -135,13 +133,11 @@
when(mMockContext.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
PID, UID)).thenReturn(PackageManager.PERMISSION_DENIED);
- replaceFeatureFlag(mMockFeatureFlag);
setTelephonyMockAsService();
}
@After
public void tearDown() throws Exception {
- replaceFeatureFlag(mRealFeatureFlagToBeRestored);
mMockContentResolver = null;
mFakeSettingsConfigProvider = null;
mRealFeatureFlagToBeRestored = null;
@@ -554,9 +550,7 @@
}
@Test
- public void testCheckSubscriptionAssociatedWithUser_badSub_flag_enabled() {
- doReturn(true).when(mMockFeatureFlag).rejectBadSubIdInteraction();
-
+ public void testCheckSubscriptionAssociatedWithUser() {
doThrow(new IllegalArgumentException("has no records on device"))
.when(mMockSubscriptionManager).isSubscriptionAssociatedWithUser(SUB_ID,
UserHandle.SYSTEM);
@@ -564,19 +558,6 @@
UserHandle.SYSTEM));
}
- @Test
- public void testCheckSubscriptionAssociatedWithUser_badSub_flag_disabled() {
- doReturn(false).when(mMockFeatureFlag).rejectBadSubIdInteraction();
-
- doThrow(new IllegalArgumentException("No records found for sub"))
- .when(mMockSubscriptionManager).isSubscriptionAssociatedWithUser(SUB_ID,
- UserHandle.SYSTEM);
- assertTrue(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext, SUB_ID,
- UserHandle.SYSTEM));
- assertTrue(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID, UserHandle.SYSTEM));
- }
-
// Put mMockTelephony into service cache so that TELEPHONY_SUPPLIER will get it.
private void setTelephonyMockAsService() throws Exception {
when(mMockTelephonyBinder.queryLocalInterface(anyString())).thenReturn(mMockTelephony);
@@ -666,13 +647,4 @@
field.setAccessible(true);
field.set(providerHolder, iContentProvider);
}
-
- private synchronized void replaceFeatureFlag(final FeatureFlags newValue)
- throws Exception {
- Field field = TelephonyPermissions.class.getDeclaredField("sFeatureFlag");
- field.setAccessible(true);
-
- mRealFeatureFlagToBeRestored = (FeatureFlags) field.get(null);
- field.set(null, newValue);
- }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 673acbc..38b4f77 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -35,6 +35,7 @@
import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.PropertyInvalidatedCache;
+import android.app.admin.DevicePolicyManager;
import android.app.usage.NetworkStatsManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -304,6 +305,7 @@
protected AppOpsManager mAppOpsManager;
protected CarrierConfigManager mCarrierConfigManager;
protected UserManager mUserManager;
+ protected DevicePolicyManager mDevicePolicyManager;
protected KeyguardManager mKeyguardManager;
protected VcnManager mVcnManager;
protected NetworkPolicyManager mNetworkPolicyManager;
@@ -630,6 +632,8 @@
mCarrierConfigManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mVcnManager = mContext.getSystemService(VcnManager.class);
mNetworkPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -685,7 +689,7 @@
doReturn(mEriManager).when(mTelephonyComponentFactory)
.makeEriManager(nullable(Phone.class), anyInt());
doReturn(mLinkBandwidthEstimator).when(mTelephonyComponentFactory)
- .makeLinkBandwidthEstimator(nullable(Phone.class));
+ .makeLinkBandwidthEstimator(nullable(Phone.class), any(Looper.class));
doReturn(mDataProfileManager).when(mTelephonyComponentFactory)
.makeDataProfileManager(any(Phone.class), any(DataNetworkController.class),
any(DataServiceManager.class), any(Looper.class),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java
index d1e5066..e45023c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java
@@ -356,7 +356,7 @@
mAccessNetworksManager.registerCallback(mMockedCallback);
- mQnsCallback.onReconnectQualifedNetworkType(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS,
+ mQnsCallback.onReconnectQualifiedNetworkType(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS,
AccessNetworkType.IWLAN);
processAllMessages();
@@ -381,7 +381,7 @@
@Test
public void testCallbackForReconnectQualifiedNetworkTypeWithFlagDisabled() throws Exception {
when(mFeatureFlags.reconnectQualifiedNetwork()).thenReturn(false);
- mQnsCallback.onReconnectQualifedNetworkType(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS,
+ mQnsCallback.onReconnectQualifiedNetworkType(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS,
AccessNetworkType.IWLAN);
processAllMessages();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index d11b730..28e129c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -51,6 +51,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
+import android.net.Uri;
import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener;
import android.net.vcn.VcnNetworkPolicyResult;
import android.os.AsyncResult;
@@ -854,6 +855,8 @@
mContextFixture.putStringArrayResource(com.android.internal.R.array
.config_force_cellular_transport_capabilities,
new String[] {"ims", "eims", "xcap"});
+ mContextFixture.putIntResource(com.android.internal.R.integer
+ .config_reevaluate_bootstrap_sim_data_usage_millis, 60000);
}
@Before
@@ -3482,9 +3485,6 @@
// Verify retry is cleared on this network
assertThat(mDataNetworkControllerUT.getDataRetryManager()
.isAnyHandoverRetryScheduled(network)).isFalse();
- // Verify the data profile is still throttled
- assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled(
- network.getDataProfile(), AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).isTrue();
}
@Test
@@ -4151,6 +4151,41 @@
}
@Test
+ public void testNetworkValidationStatusChangeCallback() throws Exception {
+ // Request not restricted network
+ TelephonyNetworkRequest request = createNetworkRequest(
+ NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ mDataNetworkControllerUT.addNetworkRequest(request);
+ processAllMessages();
+ TelephonyNetworkAgent agent = getPrivateField(getDataNetworks().get(0), "mNetworkAgent",
+ TelephonyNetworkAgent.class);
+ agent.onValidationStatus(1/*status*/, Uri.EMPTY);
+ processAllMessages();
+
+ // Verify notify
+ verify(mMockedDataNetworkControllerCallback)
+ .onInternetDataNetworkValidationStatusChanged(1);
+
+ // Request restricted network
+ mDataNetworkControllerUT.removeNetworkRequest(request);
+ getDataNetworks().get(0).tearDown(DataNetwork.TEAR_DOWN_REASON_NONE);
+ mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled(0, false, "");
+ processAllMessages();
+ clearInvocations(mMockedDataNetworkControllerCallback);
+ mDataNetworkControllerUT.addNetworkRequest(createNetworkRequest(
+ true, NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ processAllMessages();
+ agent = getPrivateField(getDataNetworks().get(0), "mNetworkAgent",
+ TelephonyNetworkAgent.class);
+ agent.onValidationStatus(1/*status*/, Uri.EMPTY);
+ processAllMessages();
+
+ // Verify not notified
+ verify(mMockedDataNetworkControllerCallback, never())
+ .onInternetDataNetworkValidationStatusChanged(anyInt());
+ }
+
+ @Test
public void testImsGracefulTearDown() throws Exception {
setImsRegistered(true);
setRcsRegistered(true);
@@ -5360,4 +5395,23 @@
verify(mMockedWwanDataServiceManager, never()).deactivateDataCall(anyInt(),
eq(DataService.REQUEST_REASON_NORMAL), any(Message.class));
}
+
+ @Test
+ public void testRadioOffTearDown() throws Exception {
+ testSetupDataNetwork();
+ doReturn(true).when(mSST).isPendingRadioPowerOffAfterDataOff();
+ mDataNetworkControllerUT.tearDownAllDataNetworks(
+ DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON);
+ processAllMessages();
+ verifyAllDataDisconnected();
+ verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false));
+
+ clearInvocations(mMockedDataNetworkControllerCallback);
+ mDataNetworkControllerUT.addNetworkRequest(
+ createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ processAllMessages();
+ verifyAllDataDisconnected();
+ verify(mMockedDataNetworkControllerCallback, never()).onAnyDataNetworkExistingChanged(
+ anyBoolean());
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index 19502f5..d5a52ea 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -256,12 +256,18 @@
private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid,
List<TrafficDescriptor> tds, Qos defaultQos) {
+ setSuccessfulSetupDataResponse(dsm, cid, tds, defaultQos,
+ PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
+ }
+
+ private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid,
+ List<TrafficDescriptor> tds, Qos defaultQos, int netwokrValidationResult) {
doAnswer(invocation -> {
final Message msg = (Message) invocation.getArguments()[10];
DataCallResponse response = createDataCallResponse(
cid, DataCallResponse.LINK_STATUS_ACTIVE, tds, defaultQos,
- PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
+ netwokrValidationResult);
msg.getData().putParcelable("data_call_response", response);
msg.arg1 = DataServiceCallback.RESULT_SUCCESS;
msg.sendToTarget();
@@ -654,6 +660,19 @@
// The final network should not have NOT_SUSPENDED because the device is OOS.
assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)).isFalse();
+
+ // Verify recreation triggers notifyDataConnection with new network agent Id.
+ ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
+ ArgumentCaptor.forClass(PreciseDataConnectionState.class);
+
+ // 4 times connecting, connected, data state changed, re-create network agent
+ verify(mPhone, times(4)).notifyDataConnection(pdcsCaptor.capture());
+ List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues();
+ assertThat(pdcsList.get(0).getState()).isEqualTo(TelephonyManager.DATA_CONNECTING);
+ assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
+ assertThat(pdcsList.get(2).getState()).isEqualTo(TelephonyManager.DATA_SUSPENDED);
+ assertThat(pdcsList.get(3).getNetId())
+ .isNotEqualTo(pdcsList.get(2).getNetId());
}
@Test
@@ -1233,6 +1252,29 @@
}
@Test
+ public void testNetworkRequestDetachedBeforeConnected() throws Exception {
+ doReturn(true).when(mFeatureFlags).keepEmptyRequestsNetwork();
+ NetworkRequestList networkRequestList = new NetworkRequestList(new TelephonyNetworkRequest(
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+ .build(), mPhone, mFeatureFlags));
+ mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+ mDataServiceManagers, mImsDataProfile, networkRequestList,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
+ mDataNetworkCallback);
+ replaceInstance(DataNetwork.class, "mDataCallSessionStats",
+ mDataNetworkUT, mDataCallSessionStats);
+
+ // Remove the request before the network connect.
+ mDataNetworkUT.detachNetworkRequest(networkRequestList.getFirst(), false/*should retry*/);
+ setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+ processAllMessages();
+
+ // Verify the request proceed to connected state even without requests.
+ assertThat(mDataNetworkUT.isConnected()).isTrue();
+ }
+
+ @Test
public void testAdminAndOwnerUids() throws Exception {
doReturn(ADMIN_UID2).when(mCarrierPrivilegesTracker).getCarrierServicePackageUid();
setupDataNetwork();
@@ -2245,6 +2287,51 @@
.isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
}
+ @Test
+ public void testHandoverWithSuccessNetworkValidation_FlagEnabled() throws Exception {
+ when(mFeatureFlags.networkValidation()).thenReturn(true);
+
+ setupDataNetwork();
+
+ setSuccessfulSetupDataResponse(
+ mMockedWlanDataServiceManager, 456, Collections.emptyList(), null,
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS);
+ TelephonyNetworkAgent mockNetworkAgent = Mockito.mock(TelephonyNetworkAgent.class);
+ replaceInstance(DataNetwork.class, "mNetworkAgent",
+ mDataNetworkUT, mockNetworkAgent);
+ // Now handover to IWLAN
+ mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null);
+ processAllMessages();
+
+ verify(mMockedWwanDataServiceManager).startHandover(eq(123), any(Message.class));
+ verify(mLinkBandwidthEstimator).unregisterCallback(any(
+ LinkBandwidthEstimatorCallback.class));
+ assertThat(mDataNetworkUT.getTransport())
+ .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ assertThat(mDataNetworkUT.getId()).isEqualTo(456);
+ verify(mDataNetworkCallback).onHandoverSucceeded(eq(mDataNetworkUT));
+
+ ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
+ ArgumentCaptor.forClass(PreciseDataConnectionState.class);
+ verify(mPhone, times(4)).notifyDataConnection(pdcsCaptor.capture());
+ List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues();
+
+ assertThat(pdcsList).hasSize(4);
+ assertThat(pdcsList.get(0).getState()).isEqualTo(TelephonyManager.DATA_CONNECTING);
+ assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
+ assertThat(pdcsList.get(1).getNetworkValidationStatus())
+ .isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
+ assertThat(pdcsList.get(2).getState())
+ .isEqualTo(TelephonyManager.DATA_HANDOVER_IN_PROGRESS);
+ assertThat(pdcsList.get(2).getNetworkValidationStatus())
+ .isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED);
+ assertThat(pdcsList.get(3).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
+ assertThat(pdcsList.get(3).getNetworkValidationStatus())
+ .isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS);
+
+ verify(mDataNetworkCallback).onHandoverSucceeded(eq(mDataNetworkUT));
+ }
+
private void setupIwlanDataNetwork() throws Exception {
// setup iwlan data network over ims
doReturn(mIwlanNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
@@ -2332,6 +2419,32 @@
// Now QNS prefers MMS on IWLAN
doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
.getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
+ // Verify an mms apn that shares the same apn name doesn't count as an alternative.
+ ApnSetting mmsApnWithSameApn = new ApnSetting.Builder()
+ .setId(2164)
+ .setOperatorNumeric("12345")
+ .setEntryName("fake_mms_apn")
+ .setApnName("fake_apn")
+ .setApnTypeBitmask(ApnSetting.TYPE_MMS)
+ .setProtocol(ApnSetting.PROTOCOL_IPV6)
+ .setRoamingProtocol(ApnSetting.PROTOCOL_IP)
+ .setCarrierEnabled(true)
+ .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN)
+ .build();
+ doReturn(new DataProfile.Builder().setApnSetting(mmsApnWithSameApn)
+ .setTrafficDescriptor(new TrafficDescriptor("fake_apn", null))
+ .build()).when(mDataProfileManager).getDataProfileForNetworkRequest(
+ any(TelephonyNetworkRequest.class),
+ eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(false), eq(false), eq(false));
+ accessNetworksManagerCallbackArgumentCaptor.getValue()
+ .onPreferredTransportChanged(NetworkCapabilities.NET_CAPABILITY_MMS, false);
+ processAllMessages();
+
+ // Check if MMS capability remains intact.
+ assertThat(mDataNetworkUT.getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue();
+
+ // Verify MMS capability is removed if using a valid MMS alternative APN.
doReturn(mMmsDataProfile).when(mDataProfileManager).getDataProfileForNetworkRequest(
any(TelephonyNetworkRequest.class),
eq(TelephonyManager.NETWORK_TYPE_IWLAN), eq(false), eq(false), eq(false));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
index 3d6b4f4..30ce46f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -1119,6 +1119,97 @@
}
@Test
+ public void testSetPreferredDataProfileBySubscriptionId() {
+ // NetworkRequest.
+ TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build(), mPhone, mFeatureFlags);
+ // DataNetwork for internet
+ DataNetwork internetNetwork = Mockito.mock(DataNetwork.class);
+
+ // Step 1. With sudId 1, connect to internet and set as prefer APN.
+ // Test for SubId 1.
+ doReturn(1).when(mPhone).getSubId();
+
+ // Sim Loaded and loads profiles.
+ changeSimStateTo(TelephonyManager.SIM_STATE_LOADED);
+ mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
+ processAllMessages();
+
+ // Find DataProfile based on network request
+ DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+ tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
+ assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
+ dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
+
+ // Connected to internet. At this time, This test expects that dataProfile is stored in
+ // mLastInternetDataProfiles for subid 1.
+ doReturn(dataProfile).when(internetNetwork).getDataProfile();
+ doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr)))
+ .when(internetNetwork).getAttachedNetworkRequestList();
+ mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged(
+ Set.of(internetNetwork));
+ processAllMessages();
+
+ // After internet connected, preferred APN should be set
+ assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
+
+
+ // Step 2. test prefer apn for subId 2.
+ // Test for SubId 2.
+ doReturn(2).when(mPhone).getSubId();
+ // Sim Loaded and loads profiles.
+ changeSimStateTo(TelephonyManager.SIM_STATE_ABSENT);
+ changeSimStateTo(TelephonyManager.SIM_STATE_LOADED);
+ mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
+ processAllMessages();
+
+ // Find DataProfile based on network request
+ dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+ tnr, TelephonyManager.NETWORK_TYPE_CDMA, false, false, false);
+ assertThat(dataProfile.getApnSetting().getApnName())
+ .isEqualTo(GENERAL_PURPOSE_APN_LEGACY_RAT);
+ dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
+ doReturn(dataProfile).when(internetNetwork).getDataProfile();
+
+ // APN reset
+ mPreferredApnId = -1;
+ mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
+ processAllMessages();
+
+ // Since a new subid has been loaded, preferred APN should be null regardless of the last
+ // internet connection of previous subid.
+ assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isFalse();
+
+
+ // Step 3. try again back to subId 1.
+ // Test for SubId 1.
+ doReturn(1).when(mPhone).getSubId();
+ // Sim Loaded and loads profiles.
+ changeSimStateTo(TelephonyManager.SIM_STATE_ABSENT);
+ changeSimStateTo(TelephonyManager.SIM_STATE_LOADED);
+ mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
+ processAllMessages();
+
+ // Find DataProfile based on network request
+ dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
+ tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
+ assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
+ dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
+ doReturn(dataProfile).when(internetNetwork).getDataProfile();
+
+ // APN reset
+ mPreferredApnId = -1;
+ mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
+ processAllMessages();
+
+ // Since the old subid has been loaded, Even if preferapn for subid 1 is not in the db, the
+ // preferapn can be loaded by mLastInternetDataProfiles
+ assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
+ }
+
+ @Test
public void testSetInitialAttachDataProfile() {
ArgumentCaptor<DataProfile> dataProfileCaptor =
ArgumentCaptor.forClass(DataProfile.class);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
index c413f83..acfa16d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
@@ -507,17 +507,38 @@
// Test: cancelPendingHandoverRetry
DataNetwork mockDn = Mockito.mock(DataNetwork.class);
+ NetworkRequest request = new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+ .build();
+ TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
+ DataNetworkController.NetworkRequestList
+ networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
+ doReturn(networkRequestList).when(mockDn).getAttachedNetworkRequestList();
+ doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mockDn).getTransport();
+ doReturn(mDataProfile3).when(mockDn).getDataProfile();
Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries");
field.setAccessible(true);
List<DataRetryEntry> mDataRetryEntries =
(List<DataRetryEntry>) field.get(mDataRetryManagerUT);
- retry = new DataHandoverRetryEntry.Builder<>()
- .setDataNetwork(mockDn)
- .build();
- mDataRetryEntries.add(retry);
- mDataRetryManagerUT.cancelPendingHandoverRetry(mockDn);
+ mDataRetryManagerUT.evaluateDataHandoverRetry(mockDn, 123, 1000);
processAllMessages();
+ mDataRetryManagerUT.cancelPendingHandoverRetry(mockDn);
+ Mockito.clearInvocations(mDataRetryManagerCallbackMock);
+ processAllMessages();
+ retry = mDataRetryEntries.get(mDataRetryEntries.size() - 1);
+ ArgumentCaptor<List<ThrottleStatus>> throttleStatusCaptor =
+ ArgumentCaptor.forClass(List.class);
+ verify(mDataRetryManagerCallbackMock).onThrottleStatusChanged(
+ throttleStatusCaptor.capture());
+ assertThat(throttleStatusCaptor.getValue()).hasSize(1);
+ ThrottleStatus throttleStatus = throttleStatusCaptor.getValue().get(0);
+ assertThat(throttleStatus.getApnType()).isEqualTo(ApnSetting.TYPE_IMS);
+ assertThat(throttleStatus.getRetryType())
+ .isEqualTo(ThrottleStatus.RETRY_TYPE_HANDOVER);
+ assertThat(throttleStatus.getThrottleExpiryTimeMillis()).isEqualTo(-1);
+ assertThat(throttleStatus.getTransportType())
+ .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
assertThat(mDataRetryManagerUT.isAnyHandoverRetryScheduled(mockDn)).isFalse();
assertThat(retry.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java
index d41be7d..dc4a58a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java
@@ -43,6 +43,7 @@
import android.net.NetworkCapabilities;
import android.os.Handler;
+import android.os.Looper;
import android.telephony.CellIdentityLte;
import android.telephony.ModemActivityInfo;
import android.telephony.NetworkRegistrationInfo;
@@ -116,7 +117,7 @@
when(mPhone.getSubId()).thenReturn(1);
when(mSignalStrength.getDbm()).thenReturn(-100);
when(mSignalStrength.getLevel()).thenReturn(1);
- mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade);
+ mLBE = new LinkBandwidthEstimator(mPhone, Looper.myLooper(), mTelephonyFacade);
mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget();
mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, false).sendToTarget();
mLBE.obtainMessage(MSG_ACTIVE_PHONE_CHANGED, 1).sendToTarget();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
index 8420acf..2a1fedb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -23,9 +23,12 @@
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
import static android.telephony.TelephonyManager.SIM_STATE_LOADED;
+import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED;
+import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGISTERED;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
import static com.android.internal.telephony.data.AutoDataSwitchController.EVALUATION_REASON_VOICE_CALL_END;
import static com.android.internal.telephony.data.PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS;
@@ -42,6 +45,7 @@
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -73,6 +77,7 @@
import androidx.test.filters.SmallTest;
+import com.android.ims.ImsException;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
@@ -84,6 +89,8 @@
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
import org.junit.After;
@@ -126,6 +133,7 @@
private ISetOpportunisticDataCallback mSetOpptDataCallback1;
private ISetOpportunisticDataCallback mSetOpptDataCallback2;
PhoneSwitcher.ImsRegTechProvider mMockImsRegTechProvider;
+ PhoneSwitcher.ImsRegisterCallback mMockImsRegisterCallback;
private SubscriptionInfo mSubscriptionInfo;
private ISub mMockedIsub;
private AutoDataSwitchController mAutoDataSwitchController;
@@ -167,6 +175,7 @@
mSetOpptDataCallback1 = mock(ISetOpportunisticDataCallback.class);
mSetOpptDataCallback2 = mock(ISetOpportunisticDataCallback.class);
mMockImsRegTechProvider = mock(PhoneSwitcher.ImsRegTechProvider.class);
+ mMockImsRegisterCallback = mock(PhoneSwitcher.ImsRegisterCallback.class);
mSubscriptionInfo = mock(SubscriptionInfo.class);
mMockedIsub = mock(ISub.class);
mAutoDataSwitchController = mock(AutoDataSwitchController.class);
@@ -871,6 +880,11 @@
mPhoneSwitcherUT.mImsRegTechProvider = mMockImsRegTechProvider;
}
+ private void mockImsRegisterCallback(int phoneId) throws ImsException {
+ doNothing().when(mMockImsRegisterCallback).setCallback(any(), eq(phoneId), any(), any());
+ mPhoneSwitcherUT.mImsRegisterCallback = mMockImsRegisterCallback;
+ }
+
@Test
@SmallTest
public void testNonDefaultDataPhoneInCall_ImsCallOnLte_shouldSwitchDds() throws Exception {
@@ -1756,6 +1770,101 @@
verify(mCommandsInterface1, never()).setDataAllowed(anyBoolean(), any());
}
+ @Test
+ @SmallTest
+ public void testRegisterForImsRegistrationCallback() throws Exception {
+ initialize();
+ setAllPhonesInactive();
+
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setSlotIndexToSubId(0, 1);
+ setSlotIndexToSubId(1, 2);
+ setDefaultDataSubId(1);
+ processAllMessages();
+
+ // Phone 0 should be the default data phoneId.
+ assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId());
+
+ doReturn(true).when(mPhone).isUserDataEnabled();
+ mockImsRegTech(0, REGISTRATION_TECH_LTE);
+ mockImsRegisterCallback(0);
+ mockImsRegisterCallback(1);
+
+ notifyImsRegistrationTechChange(mPhone);
+
+ // Verify that the callback is re-registered when the IMS registration callback is called.
+ verify(mMockImsRegisterCallback, times(2)).setCallback(any(), anyInt(), any(), any());
+ }
+
+ @Test
+ @SmallTest
+ public void testReceivingImsRegistrationTech() throws Exception {
+ doReturn(true).when(mFeatureFlags).changeMethodOfObtainingImsRegistrationRadioTech();
+
+ // Set up input and output for testing
+ ImsPhone testImsPhone = mock(ImsPhone.class);
+ doReturn(testImsPhone).when(mPhone).getImsPhone();
+ doReturn(testImsPhone).when(mPhone2).getImsPhone();
+ ImsPhoneCall testImsPhoneCall = mock(ImsPhoneCall.class);
+ doReturn(Call.State.IDLE).when(testImsPhoneCall).getState();
+ doReturn(true).when(testImsPhoneCall).isIdle();
+ doReturn(testImsPhoneCall).when(testImsPhone).getForegroundCall();
+ doReturn(testImsPhoneCall).when(testImsPhone).getBackgroundCall();
+ doReturn(testImsPhoneCall).when(testImsPhone).getRingingCall();
+
+ doNothing().when(testImsPhone).registerForImsRegistrationChanges(any(), anyInt(), any());
+
+ initialize();
+ setAllPhonesInactive();
+
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setSlotIndexToSubId(0, 1);
+ setSlotIndexToSubId(1, 2);
+ setDefaultDataSubId(1);
+ processAllMessages();
+
+ // Phone 0 should be the default data phoneId.
+ assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId());
+
+ doReturn(true).when(mPhone).isUserDataEnabled();
+ mockImsRegTech(0, REGISTRATION_TECH_NONE);
+ mockImsRegisterCallback(0);
+ mockImsRegisterCallback(1);
+
+ AsyncResult ar = new AsyncResult(null, new ImsPhone.ImsRegistrationRadioTechInfo(
+ 0, REGISTRATION_TECH_LTE, REGISTRATION_STATE_REGISTERED), null);
+ notifyImsRegistrationTechChangeWithAsyncResult(ar);
+
+ // Verify cached IMS registration tech is LTE
+ assertTrue(REGISTRATION_TECH_LTE == mPhoneSwitcherUT.mImsRegistrationRadioTechMap.get(0));
+
+ ar = new AsyncResult(null, new ImsPhone.ImsRegistrationRadioTechInfo(
+ 0, REGISTRATION_TECH_IWLAN, REGISTRATION_STATE_REGISTERED), null);
+ notifyImsRegistrationTechChangeWithAsyncResult(ar);
+
+ // Verify cached IMS registration tech is WiFi
+ assertTrue(REGISTRATION_TECH_IWLAN
+ == mPhoneSwitcherUT.mImsRegistrationRadioTechMap.get(0));
+
+ ar = new AsyncResult(null, new ImsPhone.ImsRegistrationRadioTechInfo(
+ 0, REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED), null);
+ notifyImsRegistrationTechChangeWithAsyncResult(ar);
+
+ // Verify cached IMS registration tech is NONE
+ assertTrue(REGISTRATION_TECH_NONE == mPhoneSwitcherUT.mImsRegistrationRadioTechMap.get(0));
+
+ // Verify there is no crash
+ notifyImsRegistrationTechChangeWithAsyncResult(null);
+
+ // Verify that the callback is not re-registered
+ // when the IMS registration callback is called.
+ verify(mMockImsRegisterCallback, never()).setCallback(any(), anyInt(), any(), any());
+ }
+
/* Private utility methods start here */
private void prepareIdealAutoSwitchCondition() {
@@ -1862,6 +1971,12 @@
processAllMessages();
}
+ private void notifyImsRegistrationTechChangeWithAsyncResult(AsyncResult ar) {
+ mPhoneSwitcherUT.sendMessage(
+ mPhoneSwitcherUT.obtainMessage(EVENT_IMS_RADIO_TECH_CHANGED, ar));
+ processAllMessages();
+ }
+
private Message getEcbmRegistration(Phone phone) {
ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
index 57ae9ed..e374551 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
@@ -48,6 +48,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.os.Build;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserManager;
@@ -230,6 +231,7 @@
Settings.Global.EUICC_PROVISIONED, 0);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.EUICC_PROVISIONED, 0);
+ setHasManageDevicePolicyManagedSubscriptionsPermission(false);
}
@After
@@ -894,7 +896,7 @@
@Test
@DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
- public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload()
+ public void testDownloadSubscription_adminPermission_usingSwitchAfterDownload_fails()
throws Exception {
mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
setHasWriteEmbeddedPermission(false);
@@ -909,18 +911,99 @@
when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);
- callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+ callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
+ true /* complete */,
12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
- verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR,
- 0 /* detailedCode */);
+ verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(),
any(), anyBoolean(), anyBoolean(), any(), any());
}
@Test
@DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
- public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_throws()
+ public void testDownloadSubscription_profileOwner_usingSwitchAfterDownload_fails()
+ throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+ setHasWriteEmbeddedPermission(false);
+ setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+ setUpUiccSlotData();
+ GetDownloadableSubscriptionMetadataResult result =
+ new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+ SUBSCRIPTION_WITH_METADATA);
+ doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+ doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+ doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+ prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = PACKAGE_NAME;
+ when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+ setCanManageSubscriptionOnTargetSim(false /* isTargetEuicc */, false /* hasPrivileges */);
+
+ callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */,
+ true /* complete */,
+ 12345, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+ verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
+ verify(mMockConnector, never()).downloadSubscription(anyInt(), anyInt(), any(),
+ anyBoolean(), anyBoolean(), any(), any());
+ }
+
+ @Test
+ @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+ public void testDownloadSubscription_orgOwnedProfileOwner_usingSwitchAfterDownload_success()
+ throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+ setHasWriteEmbeddedPermission(false);
+ setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+ setUpUiccSlotData();
+ GetDownloadableSubscriptionMetadataResult result =
+ new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+ SUBSCRIPTION_WITH_METADATA);
+ doReturn(true).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+ doReturn(true).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+ doReturn(false).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+ prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = PACKAGE_NAME;
+ when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+
+ callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+ EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+ verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
+ assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
+ }
+
+ @Test
+ @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+ public void testDownloadSubscription_deviceOwner_usingSwitchAfterDownload_success()
+ throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
+ setHasWriteEmbeddedPermission(false);
+ setHasManageDevicePolicyManagedSubscriptionsPermission(true);
+ setUpUiccSlotData();
+ GetDownloadableSubscriptionMetadataResult result =
+ new GetDownloadableSubscriptionMetadataResult(EuiccService.RESULT_OK,
+ SUBSCRIPTION_WITH_METADATA);
+ doReturn(false).when(mDevicePolicyManager).isProfileOwnerApp(PACKAGE_NAME);
+ doReturn(false).when(mDevicePolicyManager).isOrganizationOwnedDeviceWithManagedProfile();
+ doReturn(true).when(mDevicePolicyManager).isDeviceOwnerApp(PACKAGE_NAME);
+ prepareGetDownloadableSubscriptionMetadataCall(true /* complete */, result);
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = PACKAGE_NAME;
+ when(mPackageManager.getPackageInfo(eq(PACKAGE_NAME), anyInt())).thenReturn(pi);
+
+ callDownloadSubscription(SUBSCRIPTION, true /* switchAfterDownload */, true /* complete */,
+ EuiccService.RESULT_OK, 0 /* resolvableError */, PACKAGE_NAME /* callingPackage */);
+
+ verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
+ assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
+ }
+
+ @Test
+ @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS})
+ public void testDownloadSubscription_onlyAdminManagedAllowed_callerNotAdmin_error()
throws Exception {
mSetFlagsRule.enableFlags(Flags.FLAG_ESIM_MANAGEMENT_ENABLED);
setHasManageDevicePolicyManagedSubscriptionsPermission(false);
@@ -929,15 +1012,10 @@
.when(mUserManager)
.hasUserRestriction(UserManager.DISALLOW_SIM_GLOBALLY);
- assertThrows(SecurityException.class,
- () ->
- callDownloadSubscription(
- SUBSCRIPTION,
- false /* switchAfterDownload */,
- true /* complete */,
- EuiccService.RESULT_OK,
- 0 /* resolvableError */,
- "whatever" /* callingPackage */));
+ callDownloadSubscription(SUBSCRIPTION, false /* switchAfterDownload */, true /* complete */,
+ 12345, 0 /* resolvableError */, "whatever" /* callingPackage */);
+
+ verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */);
assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult);
}
@@ -1605,7 +1683,12 @@
@Test
@EnableCompatChanges({EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK,
TelephonyManager.ENABLE_FEATURE_MAPPING})
- public void testIsSimPortAvailable_WithTelephonyFeatureMapping() {
+ public void testIsSimPortAvailable_WithTelephonyFeatureMapping() throws Exception {
+ // Replace field to set SDK version of vendor partition to Android V
+ int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+ replaceInstance(EuiccController.class, "mVendorApiLevel", (EuiccController) mController,
+ vendorApiLevel);
+
// Feature flag enabled, device has required telephony feature.
doReturn(true).when(mFeatureFlags).enforceTelephonyFeatureMappingForPublicApis();
doReturn(true).when(mPackageManager).hasSystemFeature(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
index 17a428b..4db0bc9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java
@@ -20,12 +20,15 @@
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.os.AsyncResult;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
@@ -332,6 +335,44 @@
eq(com.android.internal.R.string.mmiErrorNotSupported));
}
+ @Test
+ public void testFacCode() {
+ // Put a valid FAC code into the carrier config.
+ CarrierConfigManager ccm = (CarrierConfigManager) mGsmCdmaPhoneUT.getContext()
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle cc = ccm.getConfigForSubId(0);
+ cc.putStringArray(CarrierConfigManager.KEY_FEATURE_ACCESS_CODES_STRING_ARRAY,
+ new String[] {"112"});
+
+ // Try using a dial string with the FAC; this should result in a NULL GsmMmiCode.
+ GsmMmiCode validFac = GsmMmiCode.newFromDialString("#112#6505551212*", mGsmCdmaPhoneUT,
+ null, null);
+ assertNull(validFac);
+
+ // Try using a dial string with the FAC; this should result in a NULL GsmMmiCode.
+ // Note this case is somewhat contrived, however the GsmMmiCode parsing does allow non-digit
+ // characters, so we will here too.
+ GsmMmiCode validFac2 = GsmMmiCode.newFromDialString("#112#650-555-1212*", mGsmCdmaPhoneUT,
+ null, null);
+ assertNull(validFac2);
+
+ // Try using a dial string with a different made up FAC; this one is not in the carrier
+ // config so should just return an MMI code.
+ GsmMmiCode invalidFac = GsmMmiCode.newFromDialString("#113#6505551212*", mGsmCdmaPhoneUT,
+ null, null);
+ assertNotNull(invalidFac);
+
+ // Now try the carrier config FAC code, but it's formatted as if it a USSD.
+ GsmMmiCode ussd = GsmMmiCode.newFromDialString("*#112*6505551212#", mGsmCdmaPhoneUT,
+ null, null);
+ assertNotNull(ussd);
+
+ // Now try the carrier config FAC code, but it's not a valid FAC formatted string
+ GsmMmiCode invalidFormat = GsmMmiCode.newFromDialString("*#112*6505551212", mGsmCdmaPhoneUT,
+ null, null);
+ assertNull(invalidFormat);
+ }
+
private void setCarrierSupportsCallerIdVerticalServiceCodesCarrierConfig() {
final PersistableBundle bundle = new PersistableBundle();
bundle.putBoolean(CarrierConfigManager
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
index 7e65048..4abf33f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java
@@ -62,6 +62,7 @@
import com.android.ims.ImsFeatureBinderRepository;
import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +114,7 @@
private BroadcastReceiver mTestBootCompleteReceiver;
private ImsServiceFeatureQueryManager.Listener mDynamicQueryListener;
private PersistableBundle[] mCarrierConfigs;
+ private FeatureFlags mFeatureFlags;
@Before
@Override
@@ -127,6 +129,7 @@
mMockQueryManagerFactory = mock(ImsResolver.ImsDynamicQueryManagerFactory.class);
mMockQueryManager = mock(ImsServiceFeatureQueryManager.class);
mMockRepo = mock(ImsFeatureBinderRepository.class);
+ mFeatureFlags = mock(FeatureFlags.class);
}
@After
@@ -1969,7 +1972,7 @@
}
mTestImsResolver = new ImsResolver(mMockContext, deviceMmTelPkgName, deviceRcsPkgName,
- numSlots, mMockRepo, Looper.myLooper());
+ numSlots, mMockRepo, Looper.myLooper(), mFeatureFlags);
mTestImsResolver.setSubscriptionManagerProxy(mTestSubscriptionManagerProxy);
mTestImsResolver.setTelephonyManagerProxy(mTestTelephonyManagerProxy);
@@ -2008,7 +2011,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository r) {
+ ImsFeatureBinderRepository r, FeatureFlags featureFlags) {
when(controller.getComponentName()).thenReturn(componentName);
return controller;
}
@@ -2118,7 +2121,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository r) {
+ ImsFeatureBinderRepository r, FeatureFlags featureFlags) {
return controllerMap.get(componentName.getPackageName());
}
});
@@ -2136,7 +2139,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository r) {
+ ImsFeatureBinderRepository r, FeatureFlags featureFlags) {
if (TEST_DEVICE_DEFAULT_NAME.getPackageName().equals(
componentName.getPackageName())) {
when(deviceController.getComponentName()).thenReturn(componentName);
@@ -2163,7 +2166,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository r) {
+ ImsFeatureBinderRepository r, FeatureFlags featureFlags) {
if (TEST_DEVICE_DEFAULT_NAME.getPackageName().equals(
componentName.getPackageName())) {
when(deviceController.getComponentName()).thenReturn(componentName);
@@ -2195,7 +2198,7 @@
@Override
public ImsServiceController create(Context context, ComponentName componentName,
ImsServiceController.ImsServiceControllerCallbacks callbacks,
- ImsFeatureBinderRepository r) {
+ ImsFeatureBinderRepository r, FeatureFlags featureFlags) {
if (TEST_DEVICE_DEFAULT_NAME.getPackageName().equals(
componentName.getPackageName())) {
when(deviceController1.getComponentName()).thenReturn(componentName);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
index 0b6aa9f..65b73fb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
@@ -57,6 +57,7 @@
import com.android.ims.ImsFeatureContainer;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.ims.internal.IImsServiceFeatureCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
@@ -126,6 +127,7 @@
IImsRegistration mMockRcsRegistration;
IImsServiceController mMockServiceControllerBinder;
ImsServiceController.ImsServiceControllerCallbacks mMockCallbacks;
+ FeatureFlags mFeatureFlags;
Context mMockContext;
private final ComponentName mTestComponentName = new ComponentName("TestPkg",
@@ -146,11 +148,12 @@
mMockRcsRegistration = mock(IImsRegistration.class);
mMockServiceControllerBinder = mock(IImsServiceController.class);
mMockCallbacks = mock(ImsServiceController.ImsServiceControllerCallbacks.class);
+ mFeatureFlags = mock(FeatureFlags.class);
mMockContext = mock(Context.class);
mRepo = new ImsFeatureBinderRepository();
mTestImsServiceController = new ImsServiceController(mMockContext, mTestComponentName,
- mMockCallbacks, mHandler, REBIND_RETRY, mRepo);
+ mMockCallbacks, mHandler, REBIND_RETRY, mRepo, mFeatureFlags);
when(mMockContext.bindService(any(), any(), anyInt())).thenReturn(true);
when(mMockServiceControllerBinder.createMmTelFeature(anyInt(), anyInt()))
.thenReturn(mMockMmTelFeature);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
index 6c4493b..58eca5d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java
@@ -40,6 +40,8 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
@@ -57,6 +59,7 @@
import com.android.internal.telephony.Call;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.GsmCdmaCall;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs;
@@ -95,6 +98,8 @@
mForeGroundCall = mock(ImsPhoneCall.class);
mBackGroundCall = mock(ImsPhoneCall.class);
mRingGroundCall = mock(ImsPhoneCall.class);
+ mTelephonyManager = mock(TelephonyManager.class);
+ mCarrierConfigManager = mock(CarrierConfigManager.class);
replaceInstance(Handler.class, "mLooper", mImsCT, Looper.myLooper());
replaceInstance(ImsPhoneCallTracker.class, "mForegroundCall", mImsCT, mForeGroundCall);
replaceInstance(ImsPhoneCallTracker.class, "mBackgroundCall", mImsCT, mBackGroundCall);
@@ -103,6 +108,10 @@
mImsCallProfile.mCallExtras = mBundle;
doReturn(ImsPhoneCall.State.IDLE).when(mForeGroundCall).getState();
+
+ // By default, turn off the business composer
+ setUserEnabledBusinessComposer(false);
+ setCarrierConfigBusinessComposer(false);
}
@After
@@ -431,6 +440,97 @@
ImsPhoneConnection.toTelecomVerificationStatus(90210));
}
+ /**
+ * Assert the helper method
+ * {@link ImsPhoneConnection#isBusinessOnlyCallComposerEnabledByUser(Phone)} is Working As
+ * Intended.
+ */
+ @Test
+ @SmallTest
+ public void testIsBusinessOnlyCallComposerEnabledByUser() {
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.isBusinessOnlyCallComposerEnabledByUser(mImsPhone));
+ setUserEnabledBusinessComposer(true);
+ assertTrue(mConnectionUT.isBusinessOnlyCallComposerEnabledByUser(mImsPhone));
+ setUserEnabledBusinessComposer(false);
+ assertFalse(mConnectionUT.isBusinessOnlyCallComposerEnabledByUser(mImsPhone));
+ }
+
+ /**
+ * Assert the helper method
+ * {@link ImsPhoneConnection#isBusinessComposerEnabledByConfig(Phone)} is Working As
+ * Intended.
+ */
+ @Test
+ @SmallTest
+ public void testBusinessComposerEnabledByCarrierConfig() {
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.isBusinessComposerEnabledByConfig(mImsPhone));
+ setCarrierConfigBusinessComposer(true);
+ assertTrue(mConnectionUT.isBusinessComposerEnabledByConfig(mImsPhone));
+ setCarrierConfigBusinessComposer(false);
+ assertFalse(mConnectionUT.isBusinessComposerEnabledByConfig(mImsPhone));
+ }
+
+ /**
+ * Verify that the {@link ImsPhoneConnection#getIsBusinessComposerFeatureEnabled()} only
+ * returns true when it is enabled by the CarrierConfigManager and user.
+ */
+ @Test
+ @SmallTest
+ public void testIncomingImsCallSetsTheBusinessComposerFeatureStatus() {
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+
+ setUserEnabledBusinessComposer(true);
+ setCarrierConfigBusinessComposer(false);
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+
+ setUserEnabledBusinessComposer(false);
+ setCarrierConfigBusinessComposer(true);
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+
+ setUserEnabledBusinessComposer(true);
+ setCarrierConfigBusinessComposer(true);
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertTrue(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+ }
+
+ /**
+ * If the business composer feature is off but ImsCallProfile extras still injected by the lower
+ * layer, Telephony should NOT inject the telecom call extras.
+ */
+ @Test
+ @SmallTest
+ public void testMaybeInjectBusinessExtrasWithFeatureOff() {
+ setUserEnabledBusinessComposer(false);
+ setCarrierConfigBusinessComposer(false);
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertFalse(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+ Bundle businessExtras = getBusinessExtras();
+ mConnectionUT.maybeInjectBusinessComposerExtras(businessExtras);
+ assertFalse(businessExtras.containsKey(android.telecom.Call.EXTRA_IS_BUSINESS_CALL));
+ assertFalse(businessExtras.containsKey(android.telecom.Call.EXTRA_ASSERTED_DISPLAY_NAME));
+ }
+
+ /**
+ * Verify if the business composer feature is on, telephony is injecting the telecom call extras
+ */
+ @Test
+ @SmallTest
+ public void testMaybeInjectBusinessExtrasWithFeatureOn() {
+ setUserEnabledBusinessComposer(true);
+ setCarrierConfigBusinessComposer(true);
+ mConnectionUT = new ImsPhoneConnection(mImsPhone, mImsCall, mImsCT, mForeGroundCall, false);
+ assertTrue(mConnectionUT.getIsBusinessComposerFeatureEnabled());
+ Bundle businessExtras = getBusinessExtras();
+ mConnectionUT.maybeInjectBusinessComposerExtras(businessExtras);
+ assertTrue(businessExtras.containsKey(android.telecom.Call.EXTRA_IS_BUSINESS_CALL));
+ assertTrue(businessExtras.containsKey(android.telecom.Call.EXTRA_ASSERTED_DISPLAY_NAME));
+ }
+
@Test
@SmallTest
public void testSetRedirectingAddress() {
@@ -481,4 +581,32 @@
latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
assertTrue(receivedCountCallback[0]);
}
+
+ private void setUserEnabledBusinessComposer(boolean isEnabled) {
+ when(mPhone.getContext()).thenReturn(mContext);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ if (isEnabled) {
+ when(mTelephonyManager.getCallComposerStatus()).thenReturn(
+ TelephonyManager.CALL_COMPOSER_STATUS_BUSINESS_ONLY);
+ } else {
+ when(mTelephonyManager.getCallComposerStatus()).thenReturn(
+ TelephonyManager.CALL_COMPOSER_STATUS_OFF);
+ }
+ }
+
+ private void setCarrierConfigBusinessComposer(boolean isEnabled) {
+ when(mPhone.getContext()).thenReturn(mContext);
+ when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
+ mCarrierConfigManager);
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(CarrierConfigManager.KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL, isEnabled);
+ when(mCarrierConfigManager.getConfigForSubId(mPhone.getSubId())).thenReturn(b);
+ }
+
+ private Bundle getBusinessExtras() {
+ Bundle businessExtras = new Bundle();
+ businessExtras.putBoolean(ImsCallProfile.EXTRA_IS_BUSINESS_CALL, true);
+ businessExtras.putString(ImsCallProfile.EXTRA_ASSERTED_DISPLAY_NAME, "Google");
+ return businessExtras;
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index 14cff4b..992f50a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -73,6 +73,7 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.sysprop.TelephonyProperties;
+import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -284,6 +285,14 @@
doReturn(Call.State.INCOMING).when(mRingingCall).getState();
assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
verify(mImsCT).acceptCall(ImsCallProfile.CALL_TYPE_VOICE);
+
+ // Verify b/286499659, fixed media type
+ doReturn(true).when(mFeatureFlags).answerAudioOnlyWhenAnsweringViaMmiCode();
+ doReturn(Call.State.IDLE).when(mForegroundCall).getState();
+ doReturn(Call.State.IDLE).when(mBackgroundCall).getState();
+ doReturn(Call.State.INCOMING).when(mRingingCall).getState();
+ assertEquals(true, mImsPhoneUT.handleInCallMmiCommands("2"));
+ verify(mImsCT).acceptCall(VideoProfile.STATE_AUDIO_ONLY);
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
index 2e64c46..5ac21f8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -34,7 +34,8 @@
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.filters.SmallTest;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyTest;
@@ -96,7 +97,7 @@
@Test
@SmallTest
public void testSetupDataCallOnCellularIms_success() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -122,7 +123,7 @@
@Test
@SmallTest
public void testSetupDataCallOnIwlan_success() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_IWLAN,
@@ -151,7 +152,7 @@
public void testSetupDataCallOnCrossSimCalling_success() {
doReturn(mCellularNetworkCapabilities)
.when(mDefaultNetworkMonitor).getNetworkCapabilities();
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_IWLAN,
@@ -178,7 +179,7 @@
@Test
@SmallTest
public void testSetupDataCallOnCellularIms_failure() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -201,7 +202,7 @@
@Test
@SmallTest
public void testHandoverFromCellularToIwlan_success() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -227,7 +228,7 @@
@Test
@SmallTest
public void testHandoverFromCellularToCrossSimCalling_success() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -256,7 +257,7 @@
@Test
@SmallTest
public void testHandoverFromCellularToIwlan_failure() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -288,7 +289,7 @@
@Test
@SmallTest
public void testSetupDataCallOnIwlan_success_thenOOS() {
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_IWLAN,
@@ -315,7 +316,7 @@
public void testIsNtn() {
when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
@@ -338,7 +339,7 @@
when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any()))
.thenReturn(false);
- mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+ mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS, false);
mDataCallSessionStats.onSetupDataCallResponse(
mDefaultImsResponse,
TelephonyManager.NETWORK_TYPE_LTE,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java
new file mode 100644
index 0000000..b9493b9
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataNetworkValidationStatsTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.metrics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyStatsLog;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+/** Test DataNetworkValidationStats */
+public class DataNetworkValidationStatsTest extends TelephonyTest {
+
+ /** Initial time at starting tests */
+ private static final Long STARTED_TIME_IN_MILLIS = 5000000L;
+
+ private TestableDataNetworkValidationStats mDataNetworkValidationStats;
+
+ /** Test Class for override elapsed time */
+ private static class TestableDataNetworkValidationStats extends DataNetworkValidationStats {
+ private long mSystemClockInMillis;
+ TestableDataNetworkValidationStats(Phone phone) {
+ super(phone);
+ mSystemClockInMillis = STARTED_TIME_IN_MILLIS;
+ }
+
+ @Override
+ protected long getTimeMillis() {
+ return mSystemClockInMillis;
+ }
+
+ public void elapseTimeInMillis(long elapse) {
+ mSystemClockInMillis += elapse;
+ }
+ }
+
+ @Before
+ public void setup() throws Exception {
+ super.setUp(getClass().getSimpleName());
+
+ mDataNetworkValidationStats = new TestableDataNetworkValidationStats(mPhone);
+ doReturn(SignalStrength.SIGNAL_STRENGTH_GREAT).when(mSignalStrength).getLevel();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mDataNetworkValidationStats = null;
+ super.tearDown();
+ }
+
+ @Test
+ public void testRequestDataNetworkValidation() {
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithSuccessStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(100L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithFailureStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_EMERGENCY);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onHandoverAttempted();
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_IWLAN);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_IWLAN,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_EMERGENCY, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(200L, proto.elapsedTimeInMillis);
+ assertTrue(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithInProgressStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithNotRequestedStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_NOT_REQUESTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationStateWithUnsupportedStatus() {
+
+ // Set up
+ doReturn(SignalStrength.SIGNAL_STRENGTH_POOR).when(mSignalStrength).getLevel();
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(300L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED,
+ TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_POOR,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_NOT_SUPPORTED,
+ proto.validationResult);
+ assertEquals(300L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+
+ @Test
+ public void testOnDataNetworkDisconnected() {
+
+ // Set up
+ doReturn(SignalStrength.SIGNAL_STRENGTH_POOR).when(mSignalStrength).getLevel();
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(300L);
+ mDataNetworkValidationStats.onDataNetworkDisconnected(TelephonyManager.NETWORK_TYPE_LTE);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_LTE,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_POOR,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_UNSPECIFIED,
+ proto.validationResult);
+ assertEquals(300L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+
+ @Test
+ public void testOnUpdateNetworkValidationState_DupStatus() {
+
+ // Test
+ mDataNetworkValidationStats.onRequestNetworkValidation(ApnSetting.TYPE_IMS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ mDataNetworkValidationStats.elapseTimeInMillis(100L);
+ mDataNetworkValidationStats.onUpdateNetworkValidationState(
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE,
+ TelephonyManager.NETWORK_TYPE_NR);
+
+ // Verify that atom was logged
+ ArgumentCaptor<PersistAtomsProto.DataNetworkValidation> captor =
+ ArgumentCaptor.forClass(PersistAtomsProto.DataNetworkValidation.class);
+ verify(mPersistAtomsStorage, times(1)).addDataNetworkValidation(
+ captor.capture());
+ PersistAtomsProto.DataNetworkValidation proto = captor.getValue();
+
+ // Make sure variables
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__NETWORK_TYPE__NETWORK_TYPE_UMTS,
+ proto.networkType);
+ assertEquals(ApnSetting.TYPE_IMS, proto.apnTypeBitmask);
+ assertEquals(
+ TelephonyStatsLog.DATA_NETWORK_VALIDATION__SIGNAL_STRENGTH__SIGNAL_STRENGTH_GREAT,
+ proto.signalStrength);
+ assertEquals(TelephonyStatsLog
+ .DATA_NETWORK_VALIDATION__VALIDATION_RESULT__VALIDATION_RESULT_SUCCESS,
+ proto.validationResult);
+ assertEquals(200L, proto.elapsedTimeInMillis);
+ assertFalse(proto.handoverAttempted);
+ assertEquals(1, proto.networkValidationCount);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
index 0426737..04b45b3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
@@ -16,9 +16,13 @@
package com.android.internal.telephony.metrics;
+import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS;
+import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ROAMING_SATELLITE_SESSION;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SERVICE_SWITCH;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SHORT_CODE_SMS;
+import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_CONFIG_UPDATER;
+import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_ENTITLEMENT;
import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.SUPPORTED_RADIO_ACCESS_FAMILY;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE;
@@ -45,9 +49,13 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;
@@ -70,8 +78,8 @@
.setCoolDownMillis(24L * 3600L * 1000L)
.build();
private static final long MIN_COOLDOWN_MILLIS = 23L * 3600L * 1000L;
- private static final long CELL_SERVICE_MIN_COOLDOWN_MILLIS =
- IS_DEBUGGABLE ? 4L * 60L * 1000L : MIN_COOLDOWN_MILLIS;
+ private static final long POWER_CORRELATED_MIN_COOLDOWN_MILLIS =
+ IS_DEBUGGABLE ? 4L * 60L * 1000L : 5L * 3600L * 1000L;
private static final long MIN_CALLS_PER_BUCKET = 5L;
// NOTE: these fields are currently 32-bit internally and padded to 64-bit by TelephonyManager
@@ -115,7 +123,7 @@
mFeatureFlags = mock(FeatureFlags.class);
mMetricsCollector =
new MetricsCollector(mContext, mPersistAtomsStorage,
- mDeviceStateHelper, mVonrHelper, mFeatureFlags);
+ mDeviceStateHelper, mVonrHelper, mDefaultNetworkMonitor, mFeatureFlags);
doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
doReturn(mServiceStateStats).when(mSST).getServiceStateStats();
}
@@ -402,6 +410,9 @@
@SmallTest
public void onPullAtom_cellularServiceState_tooFrequent() throws Exception {
doReturn(null).when(mPersistAtomsStorage).getCellularServiceStates(anyLong());
+ mContextFixture.putIntResource(
+ com.android.internal.R.integer.config_metrics_pull_cooldown_millis,
+ (int) POWER_CORRELATED_MIN_COOLDOWN_MILLIS);
List<StatsEvent> actualAtoms = new ArrayList<>();
int result = mMetricsCollector.onPullAtom(CELLULAR_SERVICE_STATE, actualAtoms);
@@ -409,7 +420,7 @@
assertThat(actualAtoms).hasSize(0);
assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
verify(mPersistAtomsStorage, times(1)).getCellularServiceStates(
- eq(CELL_SERVICE_MIN_COOLDOWN_MILLIS));
+ eq(POWER_CORRELATED_MIN_COOLDOWN_MILLIS));
verifyNoMoreInteractions(mPersistAtomsStorage);
}
@@ -469,4 +480,178 @@
assertThat(actualAtoms).hasSize(4);
assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
}
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteSession_empty() {
+ doReturn(new CarrierRoamingSatelliteSession[0]).when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteSessionStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_SESSION, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteSession_tooFrequent() {
+ doReturn(null).when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteSessionStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_SESSION, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistAtomsStorage, times(1))
+ .getCarrierRoamingSatelliteSessionStats(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteSession_multipleAtoms() {
+ CarrierRoamingSatelliteSession carrierRoamingSatelliteSession =
+ new CarrierRoamingSatelliteSession();
+ doReturn(new CarrierRoamingSatelliteSession[] {carrierRoamingSatelliteSession,
+ carrierRoamingSatelliteSession, carrierRoamingSatelliteSession,
+ carrierRoamingSatelliteSession})
+ .when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteSessionStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_SESSION, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(4);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteControllerStats_empty() {
+ doReturn(new CarrierRoamingSatelliteControllerStats[0]).when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteControllerStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS,
+ actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteControllerStats_multipleAtoms() {
+ CarrierRoamingSatelliteControllerStats carrierRoamingSatelliteControllerStats =
+ new CarrierRoamingSatelliteControllerStats();
+ doReturn(new CarrierRoamingSatelliteControllerStats[] {
+ carrierRoamingSatelliteControllerStats})
+ .when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteControllerStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS,
+ actualAtoms);
+
+ assertThat(actualAtoms).hasSize(1);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_carrierRoamingSatelliteControllerStats_tooFrequent() {
+ doReturn(null).when(mPersistAtomsStorage)
+ .getCarrierRoamingSatelliteControllerStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(CARRIER_ROAMING_SATELLITE_CONTROLLER_STATS,
+ actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistAtomsStorage, times(1))
+ .getCarrierRoamingSatelliteControllerStats(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_satelliteEntitlement_empty() {
+ doReturn(new SatelliteEntitlement[0]).when(mPersistAtomsStorage)
+ .getSatelliteEntitlementStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_ENTITLEMENT, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_satelliteEntitlement_tooFrequent() {
+ doReturn(null).when(mPersistAtomsStorage).getSatelliteEntitlementStats(
+ anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_ENTITLEMENT, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistAtomsStorage, times(1))
+ .getSatelliteEntitlementStats(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_satelliteEntitlement_multipleAtoms() {
+ SatelliteEntitlement satelliteEntitlement = new SatelliteEntitlement();
+ doReturn(new SatelliteEntitlement[] {satelliteEntitlement, satelliteEntitlement,
+ satelliteEntitlement, satelliteEntitlement})
+ .when(mPersistAtomsStorage)
+ .getSatelliteEntitlementStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_ENTITLEMENT, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(4);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_satelliteConfigUpdater_empty() {
+ doReturn(new SatelliteConfigUpdater[0]).when(mPersistAtomsStorage)
+ .getSatelliteConfigUpdaterStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_CONFIG_UPDATER, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
+
+ @Test
+ public void onPullAtom_satelliteConfigUpdater_tooFrequent() {
+ doReturn(null).when(mPersistAtomsStorage).getSatelliteConfigUpdaterStats(
+ anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_CONFIG_UPDATER, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(0);
+ assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
+ verify(mPersistAtomsStorage, times(1))
+ .getSatelliteConfigUpdaterStats(eq(MIN_COOLDOWN_MILLIS));
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onPullAtom_satelliteConfigUpdater_multipleAtoms() {
+ SatelliteConfigUpdater satelliteConfigUpdater = new SatelliteConfigUpdater();
+ doReturn(new SatelliteConfigUpdater[] {satelliteConfigUpdater, satelliteConfigUpdater,
+ satelliteConfigUpdater, satelliteConfigUpdater})
+ .when(mPersistAtomsStorage)
+ .getSatelliteConfigUpdaterStats(anyLong());
+ List<StatsEvent> actualAtoms = new ArrayList<>();
+
+ int result = mMetricsCollector.onPullAtom(SATELLITE_CONFIG_UPDATER, actualAtoms);
+
+ assertThat(actualAtoms).hasSize(4);
+ assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
index 3aad333..092522b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
@@ -62,10 +62,13 @@
import android.content.Context;
import android.os.Build;
import android.telephony.DisconnectCause;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.SatelliteProtoEnums;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyProtoEnums;
+import android.telephony.data.ApnSetting;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.SipDelegateManager;
@@ -73,9 +76,12 @@
import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.DataNetworkValidation;
import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent;
@@ -90,7 +96,9 @@
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteOutgoingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteProvision;
@@ -286,6 +294,28 @@
private SatelliteSosMessageRecommender mSatelliteSosMessageRecommender2;
private SatelliteSosMessageRecommender[] mSatelliteSosMessageRecommenders;
+ private DataNetworkValidation mDataNetworkValidationLte1;
+ private DataNetworkValidation mDataNetworkValidationLte2;
+ private DataNetworkValidation mDataNetworkValidationIwlan1;
+ private DataNetworkValidation mDataNetworkValidationIwlan2;
+ private DataNetworkValidation[] mDataNetworkValidations;
+
+ private CarrierRoamingSatelliteSession mCarrierRoamingSatelliteSession1;
+ private CarrierRoamingSatelliteSession mCarrierRoamingSatelliteSession2;
+ private CarrierRoamingSatelliteSession[] mCarrierRoamingSatelliteSessions;
+
+ private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats1;
+ private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats2;
+ private CarrierRoamingSatelliteControllerStats[] mCarrierRoamingSatelliteControllerStats;
+
+ private SatelliteEntitlement mSatelliteEntitlement1;
+ private SatelliteEntitlement mSatelliteEntitlement2;
+ private SatelliteEntitlement[] mSatelliteEntitlements;
+
+ private SatelliteConfigUpdater mSatelliteConfigUpdater1;
+ private SatelliteConfigUpdater mSatelliteConfigUpdater2;
+ private SatelliteConfigUpdater[] mSatelliteConfigUpdaters;
+
private void makeTestData() {
// MO call with SRVCC (LTE to UMTS)
mCall1Proto = new VoiceCallSession();
@@ -1070,6 +1100,10 @@
mOutgoingShortCodeSms = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1,
mOutgoingShortCodeSms2};
+
+ generateTestSatelliteData();
+
+ generateTestDataNetworkValidationsData();
}
private void generateTestSatelliteData() {
@@ -1254,6 +1288,161 @@
new SatelliteSosMessageRecommender[] {
mSatelliteSosMessageRecommender1, mSatelliteSosMessageRecommender2
};
+
+ mCarrierRoamingSatelliteSession1 = new CarrierRoamingSatelliteSession();
+ mCarrierRoamingSatelliteSession1.carrierId = 1;
+ mCarrierRoamingSatelliteSession1.isNtnRoamingInHomeCountry = false;
+ mCarrierRoamingSatelliteSession1.totalSatelliteModeTimeSec = 60;
+ mCarrierRoamingSatelliteSession1.numberOfSatelliteConnections = 3;
+ mCarrierRoamingSatelliteSession1.avgDurationOfSatelliteConnectionSec = 20;
+ mCarrierRoamingSatelliteSession1.satelliteConnectionGapMinSec = 2;
+ mCarrierRoamingSatelliteSession1.satelliteConnectionGapAvgSec = 5;
+ mCarrierRoamingSatelliteSession1.satelliteConnectionGapMaxSec = 8;
+ mCarrierRoamingSatelliteSession1.rsrpAvg = 3;
+ mCarrierRoamingSatelliteSession1.rsrpMedian = 2;
+ mCarrierRoamingSatelliteSession1.rssnrAvg = 5;
+ mCarrierRoamingSatelliteSession1.rssnrMedian = 3;
+ mCarrierRoamingSatelliteSession1.countOfIncomingSms = 2;
+ mCarrierRoamingSatelliteSession1.countOfOutgoingSms = 4;
+ mCarrierRoamingSatelliteSession1.countOfIncomingMms = 1;
+ mCarrierRoamingSatelliteSession1.countOfOutgoingMms = 1;
+
+ mCarrierRoamingSatelliteSession2 = new CarrierRoamingSatelliteSession();
+ mCarrierRoamingSatelliteSession2.carrierId = 2;
+ mCarrierRoamingSatelliteSession2.isNtnRoamingInHomeCountry = true;
+ mCarrierRoamingSatelliteSession2.totalSatelliteModeTimeSec = 120;
+ mCarrierRoamingSatelliteSession2.numberOfSatelliteConnections = 5;
+ mCarrierRoamingSatelliteSession2.avgDurationOfSatelliteConnectionSec = 20;
+ mCarrierRoamingSatelliteSession2.satelliteConnectionGapMinSec = 2;
+ mCarrierRoamingSatelliteSession2.satelliteConnectionGapAvgSec = 5;
+ mCarrierRoamingSatelliteSession2.satelliteConnectionGapMaxSec = 8;
+ mCarrierRoamingSatelliteSession2.rsrpAvg = 3;
+ mCarrierRoamingSatelliteSession2.rsrpMedian = 2;
+ mCarrierRoamingSatelliteSession2.rssnrAvg = 8;
+ mCarrierRoamingSatelliteSession2.rssnrMedian = 15;
+ mCarrierRoamingSatelliteSession2.countOfIncomingSms = 2;
+ mCarrierRoamingSatelliteSession2.countOfOutgoingSms = 4;
+ mCarrierRoamingSatelliteSession2.countOfIncomingMms = 1;
+ mCarrierRoamingSatelliteSession2.countOfOutgoingMms = 1;
+
+ mCarrierRoamingSatelliteSessions = new CarrierRoamingSatelliteSession[] {
+ mCarrierRoamingSatelliteSession1, mCarrierRoamingSatelliteSession2};
+
+ mCarrierRoamingSatelliteControllerStats1 = new CarrierRoamingSatelliteControllerStats();
+ mCarrierRoamingSatelliteControllerStats1.configDataSource =
+ SatelliteProtoEnums.CONFIG_DATA_SOURCE_ENTITLEMENT;
+ mCarrierRoamingSatelliteControllerStats1.countOfEntitlementStatusQueryRequest = 2;
+ mCarrierRoamingSatelliteControllerStats1.countOfSatelliteConfigUpdateRequest = 1;
+ mCarrierRoamingSatelliteControllerStats1.countOfSatelliteNotificationDisplayed = 1;
+ mCarrierRoamingSatelliteControllerStats1.satelliteSessionGapMinSec = 2;
+ mCarrierRoamingSatelliteControllerStats1.satelliteSessionGapAvgSec = 3;
+ mCarrierRoamingSatelliteControllerStats1.satelliteSessionGapMaxSec = 4;
+
+ mCarrierRoamingSatelliteControllerStats2 = new CarrierRoamingSatelliteControllerStats();
+ mCarrierRoamingSatelliteControllerStats2.configDataSource =
+ SatelliteProtoEnums.CONFIG_DATA_SOURCE_CONFIG_UPDATER;
+ mCarrierRoamingSatelliteControllerStats2.countOfEntitlementStatusQueryRequest = 4;
+ mCarrierRoamingSatelliteControllerStats2.countOfSatelliteConfigUpdateRequest = 1;
+ mCarrierRoamingSatelliteControllerStats2.countOfSatelliteNotificationDisplayed = 1;
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapMinSec = 5;
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapAvgSec = 10;
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapMaxSec = 15;
+
+ // CarrierRoamingSatelliteController has one data point
+ mCarrierRoamingSatelliteControllerStats = new CarrierRoamingSatelliteControllerStats[] {
+ mCarrierRoamingSatelliteControllerStats1};
+
+ mSatelliteEntitlement1 = new SatelliteEntitlement();
+ mSatelliteEntitlement1.carrierId = 1;
+ mSatelliteEntitlement1.result = 0;
+ mSatelliteEntitlement1.entitlementStatus =
+ SatelliteProtoEnums.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
+ mSatelliteEntitlement1.isRetry = false;
+ mSatelliteEntitlement1.count = 1;
+
+ mSatelliteEntitlement2 = new SatelliteEntitlement();
+ mSatelliteEntitlement2.carrierId = 2;
+ mSatelliteEntitlement2.result = 1;
+ mSatelliteEntitlement2.entitlementStatus =
+ SatelliteProtoEnums.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
+ mSatelliteEntitlement1.isRetry = true;
+ mSatelliteEntitlement2.count = 1;
+
+ mSatelliteEntitlements = new SatelliteEntitlement[] {mSatelliteEntitlement1,
+ mSatelliteEntitlement2};
+
+ mSatelliteConfigUpdater1 = new SatelliteConfigUpdater();
+ mSatelliteConfigUpdater1.configVersion = 1;
+ mSatelliteConfigUpdater1.oemConfigResult = SatelliteProtoEnums.CONFIG_UPDATE_RESULT_SUCCESS;
+ mSatelliteConfigUpdater1.carrierConfigResult =
+ SatelliteProtoEnums.CONFIG_UPDATE_RESULT_CARRIER_DATA_INVALID_PLMN;
+ mSatelliteConfigUpdater1.count = 1;
+
+ mSatelliteConfigUpdater2 = new SatelliteConfigUpdater();
+ mSatelliteConfigUpdater2.configVersion = 2;
+ mSatelliteConfigUpdater2.oemConfigResult =
+ SatelliteProtoEnums.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE;
+ mSatelliteConfigUpdater2.carrierConfigResult =
+ SatelliteProtoEnums.CONFIG_UPDATE_RESULT_SUCCESS;
+ mSatelliteConfigUpdater2.count = 1;
+
+ mSatelliteConfigUpdaters = new SatelliteConfigUpdater[] {mSatelliteConfigUpdater1,
+ mSatelliteConfigUpdater2};
+ }
+
+ private void generateTestDataNetworkValidationsData() {
+
+ // for LTE #1
+ mDataNetworkValidationLte1 = new DataNetworkValidation();
+ mDataNetworkValidationLte1.networkType = TelephonyManager.NETWORK_TYPE_LTE;
+ mDataNetworkValidationLte1.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationLte1.signalStrength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ mDataNetworkValidationLte1.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
+ mDataNetworkValidationLte1.elapsedTimeInMillis = 100L;
+ mDataNetworkValidationLte1.handoverAttempted = false;
+ mDataNetworkValidationLte1.networkValidationCount = 1;
+
+ // for LTE #2
+ mDataNetworkValidationLte2 = new DataNetworkValidation();
+ mDataNetworkValidationLte2.networkType = TelephonyManager.NETWORK_TYPE_LTE;
+ mDataNetworkValidationLte2.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationLte2.signalStrength = SignalStrength.SIGNAL_STRENGTH_GREAT;
+ mDataNetworkValidationLte2.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS;
+ mDataNetworkValidationLte2.elapsedTimeInMillis = 100L;
+ mDataNetworkValidationLte2.handoverAttempted = false;
+ mDataNetworkValidationLte2.networkValidationCount = 1;
+
+ // for IWLAN #1
+ mDataNetworkValidationIwlan1 = new DataNetworkValidation();
+ mDataNetworkValidationIwlan1.networkType = TelephonyManager.NETWORK_TYPE_IWLAN;
+ mDataNetworkValidationIwlan1.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationIwlan1.signalStrength = SignalStrength.SIGNAL_STRENGTH_POOR;
+ mDataNetworkValidationIwlan1.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE;
+ mDataNetworkValidationIwlan1.elapsedTimeInMillis = 10000L;
+ mDataNetworkValidationIwlan1.handoverAttempted = false;
+ mDataNetworkValidationIwlan1.networkValidationCount = 1;
+
+ // for IWLAN #2
+ mDataNetworkValidationIwlan2 = new DataNetworkValidation();
+ mDataNetworkValidationIwlan2.networkType = TelephonyManager.NETWORK_TYPE_IWLAN;
+ mDataNetworkValidationIwlan2.apnTypeBitmask = ApnSetting.TYPE_IMS;
+ mDataNetworkValidationIwlan2.signalStrength = SignalStrength.SIGNAL_STRENGTH_POOR;
+ mDataNetworkValidationIwlan2.validationResult =
+ PreciseDataConnectionState.NETWORK_VALIDATION_FAILURE;
+ mDataNetworkValidationIwlan2.elapsedTimeInMillis = 30000L;
+ mDataNetworkValidationIwlan2.handoverAttempted = false;
+ mDataNetworkValidationIwlan2.networkValidationCount = 1;
+
+ mDataNetworkValidations =
+ new DataNetworkValidation[] {
+ mDataNetworkValidationLte1,
+ mDataNetworkValidationLte1,
+ mDataNetworkValidationIwlan1,
+ mDataNetworkValidationIwlan2,
+ };
}
private static class TestablePersistAtomsStorage extends PersistAtomsStorage {
@@ -1421,6 +1610,22 @@
mSatelliteSosMessageRecommender1 = null;
mSatelliteSosMessageRecommender2 = null;
mSatelliteSosMessageRecommenders = null;
+ mDataNetworkValidationLte1 = null;
+ mDataNetworkValidationLte2 = null;
+ mDataNetworkValidationIwlan1 = null;
+ mDataNetworkValidationIwlan2 = null;
+ mCarrierRoamingSatelliteSession1 = null;
+ mCarrierRoamingSatelliteSession2 = null;
+ mCarrierRoamingSatelliteSessions = null;
+ mCarrierRoamingSatelliteControllerStats1 = null;
+ mCarrierRoamingSatelliteControllerStats2 = null;
+ mCarrierRoamingSatelliteControllerStats = null;
+ mSatelliteEntitlement1 = null;
+ mSatelliteEntitlement2 = null;
+ mSatelliteEntitlements = null;
+ mSatelliteConfigUpdater1 = null;
+ mSatelliteConfigUpdater2 = null;
+ mSatelliteConfigUpdaters = null;
super.tearDown();
}
@@ -4576,6 +4781,476 @@
}
@Test
+ public void addCarrierRoamingSatelliteSessionStats_emptyProto() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteSessionStats(
+ mCarrierRoamingSatelliteSession1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ CarrierRoamingSatelliteSession[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(0L);
+ assertProtoArrayEquals(new CarrierRoamingSatelliteSession[] {
+ mCarrierRoamingSatelliteSession1}, output);
+ }
+
+ @Test
+ public void addCarrierRoamingSatelliteSessionStats_withExistingEntries() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteSessionStats(
+ mCarrierRoamingSatelliteSession1);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteSessionStats(
+ mCarrierRoamingSatelliteSession2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ CarrierRoamingSatelliteSession[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new CarrierRoamingSatelliteSession[] {mCarrierRoamingSatelliteSession2}, output);
+ }
+
+ @Test
+ public void addCarrierRoamingSatelliteSessionStats_tooManyEntries() throws Exception {
+ createEmptyTestFile();
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ // Store atoms up to maximum number + 1
+ int maxCount = 1 + 1;
+ for (int i = 0; i < maxCount; i++) {
+ mPersistAtomsStorage.addCarrierRoamingSatelliteSessionStats(
+ copyOf(mCarrierRoamingSatelliteSession1));
+ mPersistAtomsStorage.incTimeMillis(100L);
+ }
+
+ // Store 1 different atom
+ mPersistAtomsStorage.addCarrierRoamingSatelliteSessionStats(
+ mCarrierRoamingSatelliteSession2);
+
+ verifyCurrentStateSavedToFileOnce();
+
+ CarrierRoamingSatelliteSession[] result =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(0L);
+
+ // First atom has count 0, the other has 1
+ assertHasStatsAndCount(result, mCarrierRoamingSatelliteSession1, 0);
+ assertHasStatsAndCount(result, mCarrierRoamingSatelliteSession2, 1);
+ }
+
+ @Test
+ public void getCarrierRoamingSatelliteSessionStats_tooFrequent() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
+ CarrierRoamingSatelliteSession[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(100L);
+
+ // Should be denied
+ assertNull(output);
+ }
+
+ @Test
+ public void getCarrierRoamingSatelliteSessionStats_withSavedAtoms() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ CarrierRoamingSatelliteSession[] carrierRoamingSatelliteSessionStatsList1 =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(50L);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ CarrierRoamingSatelliteSession[] carrierRoamingSatelliteSessionStatsList2 =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteSessionStats(50L);
+
+ // First set of results should be equal to file contents.
+ CarrierRoamingSatelliteSession[] expectedList = new CarrierRoamingSatelliteSession[] {
+ mCarrierRoamingSatelliteSession1, mCarrierRoamingSatelliteSession2};
+ assertProtoArrayEqualsIgnoringOrder(expectedList, carrierRoamingSatelliteSessionStatsList1);
+ // Second set of results should be empty.
+ assertProtoArrayEquals(new CarrierRoamingSatelliteSession[0],
+ carrierRoamingSatelliteSessionStatsList2);
+ // Corresponding pull timestamp should be updated and saved.
+ assertEquals(START_TIME_MILLIS + 200L, mPersistAtomsStorage
+ .getAtomsProto().carrierRoamingSatelliteSessionPullTimestampMillis);
+ InOrder inOrder = inOrder(mTestFileOutputStream);
+ assertEquals(START_TIME_MILLIS + 100L,
+ getAtomsWritten(inOrder).carrierRoamingSatelliteSessionPullTimestampMillis);
+ assertEquals(START_TIME_MILLIS + 200L,
+ getAtomsWritten(inOrder).carrierRoamingSatelliteSessionPullTimestampMillis);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void addCarrierRoamingSatelliteControllerStats_emptyProto() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteControllerStats(
+ mCarrierRoamingSatelliteControllerStats1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ CarrierRoamingSatelliteControllerStats[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteControllerStats(0L);
+ assertProtoArrayEquals(new CarrierRoamingSatelliteControllerStats[] {
+ mCarrierRoamingSatelliteControllerStats1}, output);
+ }
+
+ @Test
+ public void addCarrierRoamingSatelliteControllerStats_withExistingEntries() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteControllerStats(
+ mCarrierRoamingSatelliteControllerStats1);
+ mPersistAtomsStorage.addCarrierRoamingSatelliteControllerStats(
+ mCarrierRoamingSatelliteControllerStats2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ CarrierRoamingSatelliteControllerStats expected =
+ new CarrierRoamingSatelliteControllerStats();
+ expected.configDataSource = mCarrierRoamingSatelliteControllerStats2.configDataSource;
+ expected.countOfEntitlementStatusQueryRequest =
+ mCarrierRoamingSatelliteControllerStats1.countOfEntitlementStatusQueryRequest
+ + mCarrierRoamingSatelliteControllerStats2
+ .countOfEntitlementStatusQueryRequest;
+ expected.countOfSatelliteConfigUpdateRequest =
+ mCarrierRoamingSatelliteControllerStats1.countOfSatelliteConfigUpdateRequest
+ + mCarrierRoamingSatelliteControllerStats2
+ .countOfSatelliteConfigUpdateRequest;
+ expected.countOfSatelliteNotificationDisplayed =
+ mCarrierRoamingSatelliteControllerStats1.countOfSatelliteNotificationDisplayed
+ + mCarrierRoamingSatelliteControllerStats2
+ .countOfSatelliteNotificationDisplayed;
+ expected.satelliteSessionGapMinSec =
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapMinSec;
+ expected.satelliteSessionGapAvgSec =
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapAvgSec;
+ expected.satelliteSessionGapMaxSec =
+ mCarrierRoamingSatelliteControllerStats2.satelliteSessionGapMaxSec;
+
+ verifyCurrentStateSavedToFileOnce();
+ CarrierRoamingSatelliteControllerStats[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteControllerStats(0L);
+ assertHasStats(output, expected);
+ }
+
+ @Test
+ public void getCarrierRoamingSatelliteControllerStats_tooFrequent() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
+ CarrierRoamingSatelliteControllerStats[] output =
+ mPersistAtomsStorage.getCarrierRoamingSatelliteControllerStats(100L);
+
+ // Should be denied
+ assertNull(output);
+ }
+
+
+ @Test
+ public void addSatelliteEntitlementStats_emptyProto() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteEntitlementStats(mSatelliteEntitlement1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteEntitlement[] output =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(0L);
+ assertProtoArrayEquals(new SatelliteEntitlement[] {mSatelliteEntitlement1}, output);
+ }
+
+ @Test
+ public void addSatelliteEntitlementStats_withExistingEntries() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteEntitlementStats(mSatelliteEntitlement1);
+ mPersistAtomsStorage.addSatelliteEntitlementStats(mSatelliteEntitlement2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteEntitlement[] output =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new SatelliteEntitlement[] {
+ mSatelliteEntitlement1, mSatelliteEntitlement2}, output);
+ }
+
+ @Test
+ public void addSatelliteEntitlementStats_updateExistingEntries() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteEntitlementStats(copyOf(mSatelliteEntitlement1));
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // Count should be increased by 1.
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteEntitlement newSatelliteEntitlement1 = copyOf(mSatelliteEntitlement1);
+ newSatelliteEntitlement1.count = 2;
+ SatelliteEntitlement[] expectedList = new SatelliteEntitlement[] {newSatelliteEntitlement1,
+ mSatelliteEntitlement2};
+ assertProtoArrayEqualsIgnoringOrder(expectedList,
+ mPersistAtomsStorage.getSatelliteEntitlementStats(0L));
+ }
+
+ @Test
+ public void addSatelliteEntitlementStats_tooManyEntries() throws Exception {
+ createEmptyTestFile();
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ // Store atoms up to maximum number + 1
+ int maxCount = 15 + 1;
+ for (int i = 0; i < maxCount; i++) {
+ mPersistAtomsStorage.addSatelliteEntitlementStats(mSatelliteEntitlement1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ }
+
+ // Store 1 different atom
+ mPersistAtomsStorage.addSatelliteEntitlementStats(mSatelliteEntitlement2);
+
+ verifyCurrentStateSavedToFileOnce();
+
+ SatelliteEntitlement[] result =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(0L);
+
+ // First atom has count 14, the other has 1
+ assertHasStatsAndCount(result, mSatelliteEntitlement1, 16);
+ assertHasStatsAndCount(result, mSatelliteEntitlement2, 1);
+ }
+
+ @Test
+ public void getSatelliteEntitlementStats_tooFrequent() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
+ SatelliteEntitlement[] output =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(100L);
+
+ // Should be denied
+ assertNull(output);
+ }
+
+ @Test
+ public void getSatelliteEntitlementStats_withSavedAtoms() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ SatelliteEntitlement[] satelliteEntitlementStatsList1 =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(50L);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ SatelliteEntitlement[] satelliteEntitlementStatsList2 =
+ mPersistAtomsStorage.getSatelliteEntitlementStats(50L);
+
+ // First set of results should be equal to file contents.
+ SatelliteEntitlement[] expectedList = new SatelliteEntitlement[] {
+ mSatelliteEntitlement1, mSatelliteEntitlement2};
+ assertProtoArrayEqualsIgnoringOrder(expectedList, satelliteEntitlementStatsList1);
+ // Second set of results should be empty.
+ assertProtoArrayEquals(new SatelliteEntitlement[0], satelliteEntitlementStatsList2);
+ // Corresponding pull timestamp should be updated and saved.
+ assertEquals(START_TIME_MILLIS + 200L, mPersistAtomsStorage
+ .getAtomsProto().satelliteEntitlementPullTimestampMillis);
+ InOrder inOrder = inOrder(mTestFileOutputStream);
+ assertEquals(START_TIME_MILLIS + 100L,
+ getAtomsWritten(inOrder).satelliteEntitlementPullTimestampMillis);
+ assertEquals(START_TIME_MILLIS + 200L,
+ getAtomsWritten(inOrder).satelliteEntitlementPullTimestampMillis);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void addSatelliteConfigUpdaterStats_emptyProto() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(mSatelliteConfigUpdater1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteConfigUpdater[] output =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(0L);
+ assertProtoArrayEquals(new SatelliteConfigUpdater[] {mSatelliteConfigUpdater1}, output);
+ }
+
+ @Test
+ public void addSatelliteConfigUpdaterStats_withExistingEntries() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(mSatelliteConfigUpdater1);
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(mSatelliteConfigUpdater2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteConfigUpdater[] output =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(0L);
+ assertProtoArrayEqualsIgnoringOrder(new SatelliteConfigUpdater[] {
+ mSatelliteConfigUpdater1, mSatelliteConfigUpdater2}, output);
+ }
+
+ @Test
+ public void addSatelliteConfigUpdaterStats_updateExistingEntries() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(copyOf(mSatelliteConfigUpdater1));
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // Count should be increased by 1.
+ verifyCurrentStateSavedToFileOnce();
+ SatelliteConfigUpdater newSatelliteConfigUpdater1 = copyOf(mSatelliteConfigUpdater1);
+ newSatelliteConfigUpdater1.count = 2;
+ SatelliteConfigUpdater[] expectedList = new SatelliteConfigUpdater[] {
+ newSatelliteConfigUpdater1, mSatelliteConfigUpdater2};
+ assertProtoArrayEqualsIgnoringOrder(expectedList,
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(0L));
+ }
+
+ @Test
+ public void addSatelliteConfigUpdaterStats_tooManyEntries() throws Exception {
+ createEmptyTestFile();
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ // Store atoms up to maximum number + 1
+ int maxCount = 15 + 1;
+ for (int i = 0; i < maxCount; i++) {
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(mSatelliteConfigUpdater1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ }
+
+ // Store 1 different atom
+ mPersistAtomsStorage.addSatelliteConfigUpdaterStats(mSatelliteConfigUpdater2);
+
+ verifyCurrentStateSavedToFileOnce();
+
+ SatelliteConfigUpdater[] result =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(0L);
+
+ // First atom has count 14, the other has 1
+ assertHasStatsAndCount(result, mSatelliteConfigUpdater1, 16);
+ assertHasStatsAndCount(result, mSatelliteConfigUpdater2, 1);
+ }
+
+ @Test
+ public void getSatelliteConfigUpdaterStats_tooFrequent() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
+ SatelliteConfigUpdater[] output =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(100L);
+
+ // Should be denied
+ assertNull(output);
+ }
+
+ @Test
+ public void getSatelliteConfigUpdaterStats_withSavedAtoms() throws Exception {
+ createTestFile(START_TIME_MILLIS);
+
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ SatelliteConfigUpdater[] satelliteConfigUpdaterStatsList1 =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(50L);
+ mPersistAtomsStorage.incTimeMillis(100L);
+ SatelliteConfigUpdater[] satelliteConfigUpdaterStatsList2 =
+ mPersistAtomsStorage.getSatelliteConfigUpdaterStats(50L);
+
+ // First set of results should be equal to file contents.
+ SatelliteConfigUpdater[] expectedList = new SatelliteConfigUpdater[] {
+ mSatelliteConfigUpdater1, mSatelliteConfigUpdater2};
+ assertProtoArrayEqualsIgnoringOrder(expectedList, satelliteConfigUpdaterStatsList1);
+ // Second set of results should be empty.
+ assertProtoArrayEquals(new SatelliteConfigUpdater[0], satelliteConfigUpdaterStatsList2);
+ // Corresponding pull timestamp should be updated and saved.
+ assertEquals(START_TIME_MILLIS + 200L, mPersistAtomsStorage
+ .getAtomsProto().satelliteConfigUpdaterPullTimestampMillis);
+ InOrder inOrder = inOrder(mTestFileOutputStream);
+ assertEquals(START_TIME_MILLIS + 100L,
+ getAtomsWritten(inOrder).satelliteConfigUpdaterPullTimestampMillis);
+ assertEquals(START_TIME_MILLIS + 200L,
+ getAtomsWritten(inOrder).satelliteConfigUpdaterPullTimestampMillis);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ @SmallTest
+ public void addDataNetworkValidation_newEntry() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationIwlan1);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // There should be 2 DataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output = mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new DataNetworkValidation[] {
+ mDataNetworkValidationLte1, mDataNetworkValidationIwlan1},
+ output);
+ }
+
+ @Test
+ public void addDataNetworkValidation_existingEntry() throws Exception {
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ int expectedNetworkValidationCount =
+ mDataNetworkValidationLte1.networkValidationCount
+ + mDataNetworkValidationLte2.networkValidationCount;
+
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte2);
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ DataNetworkValidation expected = copyOf(mDataNetworkValidationLte1);
+ expected.networkValidationCount = expectedNetworkValidationCount;
+
+ // There should be 1 DataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output =
+ mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertProtoArrayEqualsIgnoringOrder(
+ new DataNetworkValidation[] {expected},
+ output);
+ }
+
+ @Test
+ public void addDataNetworkValidation_tooManyEntries() throws Exception {
+
+ // Set up
+ doReturn(false).when(mPackageManager).hasSystemFeature(anyString());
+
+ createEmptyTestFile();
+ mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
+
+ // Currently, the maximum number that can be stored for DataNetworkValidation in Atom
+ // storage is 15. Try saving excess.
+ int maxNumDataNetworkValidation = 20;
+ mPersistAtomsStorage.addDataNetworkValidation(mDataNetworkValidationLte1);
+ for (int i = 0; i < maxNumDataNetworkValidation; i++) {
+ DataNetworkValidation copied = copyOf(mDataNetworkValidationLte1);
+ copied.apnTypeBitmask = mDataNetworkValidationLte1.apnTypeBitmask + i;
+ mPersistAtomsStorage.addDataNetworkValidation(copied);
+ }
+ mPersistAtomsStorage.incTimeMillis(100L);
+
+ // There should be less than or equal to maxNumDataNetworkValidation
+ verifyCurrentStateSavedToFileOnce();
+ DataNetworkValidation[] output =
+ mPersistAtomsStorage.getDataNetworkValidation(0L);
+ assertTrue(output.length <= maxNumDataNetworkValidation);
+ }
+
+ @Test
@SmallTest
public void clearAtoms() throws Exception {
createTestFile(START_TIME_MILLIS);
@@ -4660,6 +5335,16 @@
atoms.satelliteProvisionPullTimestampMillis = lastPullTimeMillis;
atoms.satelliteSosMessageRecommender = mSatelliteSosMessageRecommenders;
atoms.satelliteSosMessageRecommenderPullTimestampMillis = lastPullTimeMillis;
+ atoms.dataNetworkValidation = mDataNetworkValidations;
+ atoms.dataNetworkValidationPullTimestampMillis = lastPullTimeMillis;
+ atoms.carrierRoamingSatelliteSession = mCarrierRoamingSatelliteSessions;
+ atoms.carrierRoamingSatelliteSessionPullTimestampMillis = lastPullTimeMillis;
+ atoms.carrierRoamingSatelliteControllerStats = mCarrierRoamingSatelliteControllerStats;
+ atoms.carrierRoamingSatelliteControllerStatsPullTimestampMillis = lastPullTimeMillis;
+ atoms.satelliteEntitlement = mSatelliteEntitlements;
+ atoms.satelliteEntitlementPullTimestampMillis = lastPullTimeMillis;
+ atoms.satelliteConfigUpdater = mSatelliteConfigUpdaters;
+ atoms.satelliteConfigUpdaterPullTimestampMillis = lastPullTimeMillis;
FileOutputStream stream = new FileOutputStream(mTestFile);
stream.write(PersistAtoms.toByteArray(atoms));
stream.close();
@@ -4823,6 +5508,29 @@
return SatelliteSosMessageRecommender.parseFrom(MessageNano.toByteArray(source));
}
+ private static DataNetworkValidation copyOf(DataNetworkValidation source)
+ throws Exception {
+ return DataNetworkValidation.parseFrom(MessageNano.toByteArray(source));
+ }
+
+ private static CarrierRoamingSatelliteSession copyOf(CarrierRoamingSatelliteSession source)
+ throws Exception {
+ return CarrierRoamingSatelliteSession.parseFrom(MessageNano.toByteArray(source));
+ }
+
+ private static CarrierRoamingSatelliteControllerStats copyOf(
+ CarrierRoamingSatelliteControllerStats source) throws Exception {
+ return CarrierRoamingSatelliteControllerStats.parseFrom(MessageNano.toByteArray(source));
+ }
+
+ private static SatelliteEntitlement copyOf(SatelliteEntitlement source) throws Exception {
+ return SatelliteEntitlement.parseFrom(MessageNano.toByteArray(source));
+ }
+
+ private static SatelliteConfigUpdater copyOf(SatelliteConfigUpdater source) throws Exception {
+ return SatelliteConfigUpdater.parseFrom(MessageNano.toByteArray(source));
+ }
+
private void assertAllPullTimestampEquals(long timestamp) {
assertEquals(
timestamp,
@@ -5321,4 +6029,82 @@
}
assertEquals(expectedCount, actualCount);
}
+
+ private static void assertHasStatsAndCount(CarrierRoamingSatelliteSession[] tested,
+ @Nullable CarrierRoamingSatelliteSession expectedStats, int expectedCount) {
+ assertNotNull(tested);
+ int actualCount = 0;
+ for (CarrierRoamingSatelliteSession stats : tested) {
+ if (stats.carrierId == expectedStats.carrierId
+ && stats.isNtnRoamingInHomeCountry == expectedStats.isNtnRoamingInHomeCountry
+ && stats.totalSatelliteModeTimeSec == expectedStats.totalSatelliteModeTimeSec
+ && stats.numberOfSatelliteConnections
+ == expectedStats.numberOfSatelliteConnections
+ && stats.avgDurationOfSatelliteConnectionSec
+ == expectedStats.avgDurationOfSatelliteConnectionSec
+ && stats.satelliteConnectionGapMinSec
+ == expectedStats.satelliteConnectionGapMinSec
+ && stats.satelliteConnectionGapAvgSec
+ == expectedStats.satelliteConnectionGapAvgSec
+ && stats.satelliteConnectionGapMaxSec
+ == expectedStats.satelliteConnectionGapMaxSec
+ && stats.rsrpAvg == expectedStats.rsrpAvg
+ && stats.rsrpMedian == expectedStats.rsrpMedian
+ && stats.rssnrAvg == expectedStats.rssnrAvg
+ && stats.rssnrMedian == expectedStats.rssnrMedian
+ && stats.countOfIncomingSms == expectedStats.countOfIncomingSms
+ && stats.countOfOutgoingSms == expectedStats.countOfOutgoingSms
+ && stats.countOfIncomingMms == expectedStats.countOfIncomingMms
+ && stats.countOfOutgoingMms == expectedStats.countOfOutgoingMms) {
+ actualCount++;
+ }
+ }
+ assertEquals(expectedCount, actualCount);
+ }
+
+ private static void assertHasStats(CarrierRoamingSatelliteControllerStats[] tested,
+ @Nullable CarrierRoamingSatelliteControllerStats expectedStats) {
+ assertNotNull(tested);
+ assertEquals(tested[0].configDataSource, expectedStats.configDataSource);
+ assertEquals(tested[0].countOfEntitlementStatusQueryRequest,
+ expectedStats.countOfEntitlementStatusQueryRequest);
+ assertEquals(tested[0].countOfSatelliteConfigUpdateRequest,
+ expectedStats.countOfSatelliteConfigUpdateRequest);
+ assertEquals(tested[0].countOfSatelliteNotificationDisplayed,
+ expectedStats.countOfSatelliteNotificationDisplayed);
+ assertEquals(tested[0].satelliteSessionGapMinSec, expectedStats.satelliteSessionGapMinSec);
+ assertEquals(tested[0].satelliteSessionGapAvgSec, expectedStats.satelliteSessionGapAvgSec);
+ assertEquals(tested[0].satelliteSessionGapMaxSec, expectedStats.satelliteSessionGapMaxSec);
+ }
+
+ private static void assertHasStatsAndCount(
+ SatelliteEntitlement[] tested,
+ @Nullable SatelliteEntitlement expectedStats, int expectedCount) {
+ assertNotNull(tested);
+ int actualCount = 0;
+ for (SatelliteEntitlement stats : tested) {
+ if (stats.carrierId == expectedStats.carrierId
+ && stats.result == expectedStats.result
+ && stats.entitlementStatus == expectedStats.entitlementStatus
+ && stats.isRetry == expectedStats.isRetry) {
+ actualCount = stats.count;
+ }
+ }
+ assertEquals(expectedCount, actualCount);
+ }
+
+ private static void assertHasStatsAndCount(
+ SatelliteConfigUpdater[] tested,
+ @Nullable SatelliteConfigUpdater expectedStats, int expectedCount) {
+ assertNotNull(tested);
+ int actualCount = 0;
+ for (SatelliteConfigUpdater stats : tested) {
+ if (stats.configVersion == expectedStats.configVersion
+ && stats.oemConfigResult == expectedStats.oemConfigResult
+ && stats.carrierConfigResult == expectedStats.carrierConfigResult) {
+ actualCount = stats.count;
+ }
+ }
+ assertEquals(expectedCount, actualCount);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
index 9a84224..a7f1e01 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
@@ -24,7 +24,11 @@
import android.telephony.TelephonyProtoEnums;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
+import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteConfigUpdater;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController;
+import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteEntitlement;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteIncomingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteOutgoingDatagram;
import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteProvision;
@@ -296,4 +300,136 @@
stats.isSatelliteAllowedInCurrentLocation);
verifyNoMoreInteractions(mPersistAtomsStorage);
}
+
+ @Test
+ public void onCarrierRoamingSatelliteSessionMetrics_withAtoms() throws Exception {
+ SatelliteStats.CarrierRoamingSatelliteSessionParams param =
+ new SatelliteStats.CarrierRoamingSatelliteSessionParams.Builder()
+ .setCarrierId(100)
+ .setIsNtnRoamingInHomeCountry(true)
+ .setTotalSatelliteModeTimeSec(10 * 60)
+ .setNumberOfSatelliteConnections(5)
+ .setAvgDurationOfSatelliteConnectionSec(2 * 60)
+ .setSatelliteConnectionGapMinSec(30)
+ .setSatelliteConnectionGapAvgSec(300)
+ .setSatelliteConnectionGapMaxSec(500)
+ .setRsrpAvg(2)
+ .setRsrpMedian(3)
+ .setRssnrAvg(12)
+ .setRssnrMedian(18)
+ .setCountOfIncomingSms(6)
+ .setCountOfOutgoingSms(11)
+ .setCountOfIncomingMms(9)
+ .setCountOfOutgoingMms(14)
+ .build();
+
+ mSatelliteStats.onCarrierRoamingSatelliteSessionMetrics(param);
+
+ ArgumentCaptor<CarrierRoamingSatelliteSession> captor =
+ ArgumentCaptor.forClass(CarrierRoamingSatelliteSession.class);
+ verify(mPersistAtomsStorage).addCarrierRoamingSatelliteSessionStats(captor.capture());
+ CarrierRoamingSatelliteSession stats = captor.getValue();
+ assertEquals(param.getCarrierId(), stats.carrierId);
+ assertEquals(param.getIsNtnRoamingInHomeCountry(), stats.isNtnRoamingInHomeCountry);
+ assertEquals(param.getTotalSatelliteModeTimeSec(), stats.totalSatelliteModeTimeSec);
+ assertEquals(param.getNumberOfSatelliteConnections(), stats.numberOfSatelliteConnections);
+ assertEquals(param.getAvgDurationOfSatelliteConnectionSec(),
+ stats.avgDurationOfSatelliteConnectionSec);
+ assertEquals(param.getSatelliteConnectionGapMinSec(), stats.satelliteConnectionGapMinSec);
+ assertEquals(param.getSatelliteConnectionGapAvgSec(), stats.satelliteConnectionGapAvgSec);
+ assertEquals(param.getSatelliteConnectionGapMaxSec(), stats.satelliteConnectionGapMaxSec);
+ assertEquals(param.getRsrpAvg(), stats.rsrpAvg);
+ assertEquals(param.getRsrpMedian(), stats.rsrpMedian);
+ assertEquals(param.getRssnrAvg(), stats.rssnrAvg);
+ assertEquals(param.getRssnrMedian(), stats.rssnrMedian);
+ assertEquals(param.getCountOfIncomingSms(), stats.countOfIncomingSms);
+ assertEquals(param.getCountOfOutgoingSms(), stats.countOfOutgoingSms);
+ assertEquals(param.getCountOfIncomingMms(), stats.countOfIncomingMms);
+ assertEquals(param.getCountOfOutgoingMms(), stats.countOfOutgoingMms);
+
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onCarrierRoamingSatelliteControllerStatsMetrics_withAtoms() throws Exception {
+ SatelliteStats.CarrierRoamingSatelliteControllerStatsParams param =
+ new SatelliteStats.CarrierRoamingSatelliteControllerStatsParams.Builder()
+ .setConfigDataSource(4)
+ .setCountOfEntitlementStatusQueryRequest(6)
+ .setCountOfSatelliteConfigUpdateRequest(2)
+ .setCountOfSatelliteNotificationDisplayed(1)
+ .setSatelliteSessionGapMinSec(15)
+ .setSatelliteSessionGapAvgSec(30)
+ .setSatelliteSessionGapMaxSec(45)
+ .build();
+
+ mSatelliteStats.onCarrierRoamingSatelliteControllerStatsMetrics(param);
+
+ ArgumentCaptor<CarrierRoamingSatelliteControllerStats> captor =
+ ArgumentCaptor.forClass(CarrierRoamingSatelliteControllerStats.class);
+ verify(mPersistAtomsStorage).addCarrierRoamingSatelliteControllerStats(captor.capture());
+ CarrierRoamingSatelliteControllerStats stats = captor.getValue();
+ assertEquals(param.getConfigDataSource(), stats.configDataSource);
+ assertEquals(param.getCountOfEntitlementStatusQueryRequest(),
+ stats.countOfEntitlementStatusQueryRequest);
+ assertEquals(param.getCountOfSatelliteConfigUpdateRequest(),
+ stats.countOfSatelliteConfigUpdateRequest);
+ assertEquals(param.getCountOfSatelliteNotificationDisplayed(),
+ stats.countOfSatelliteNotificationDisplayed);
+ assertEquals(param.getSatelliteSessionGapMinSec(), stats.satelliteSessionGapMinSec);
+ assertEquals(param.getSatelliteSessionGapAvgSec(), stats.satelliteSessionGapAvgSec);
+ assertEquals(param.getSatelliteSessionGapMaxSec(), stats.satelliteSessionGapMaxSec);
+
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onSatelliteEntitlementMetrics_withAtoms() throws Exception {
+ SatelliteStats.SatelliteEntitlementParams param =
+ new SatelliteStats.SatelliteEntitlementParams.Builder()
+ .setCarrierId(10)
+ .setResult(500)
+ .setEntitlementStatus(2)
+ .setIsRetry(true)
+ .setCount(5)
+ .build();
+
+ mSatelliteStats.onSatelliteEntitlementMetrics(param);
+
+ ArgumentCaptor<SatelliteEntitlement> captor =
+ ArgumentCaptor.forClass(SatelliteEntitlement.class);
+ verify(mPersistAtomsStorage).addSatelliteEntitlementStats(captor.capture());
+ SatelliteEntitlement stats = captor.getValue();
+ assertEquals(param.getCarrierId(), stats.carrierId);
+ assertEquals(param.getResult(), stats.result);
+ assertEquals(param.getEntitlementStatus(), stats.entitlementStatus);
+ assertEquals(param.getIsRetry(), stats.isRetry);
+ assertEquals(param.getCount(), stats.count);
+
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ public void onSatelliteConfigUpdaterMetrics_withAtoms() throws Exception {
+ SatelliteStats.SatelliteConfigUpdaterParams param =
+ new SatelliteStats.SatelliteConfigUpdaterParams.Builder()
+ .setConfigVersion(8)
+ .setOemConfigResult(9)
+ .setCarrierConfigResult(7)
+ .setCount(3)
+ .build();
+
+ mSatelliteStats.onSatelliteConfigUpdaterMetrics(param);
+
+ ArgumentCaptor<SatelliteConfigUpdater> captor =
+ ArgumentCaptor.forClass(SatelliteConfigUpdater.class);
+ verify(mPersistAtomsStorage).addSatelliteConfigUpdaterStats(captor.capture());
+ SatelliteConfigUpdater stats = captor.getValue();
+ assertEquals(param.getConfigVersion(), stats.configVersion);
+ assertEquals(param.getOemConfigResult(), stats.oemConfigResult);
+ assertEquals(param.getCarrierConfigResult(), stats.carrierConfigResult);
+ assertEquals(param.getCount(), stats.count);
+
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
index 76118c4..e409b8d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/security/CellularNetworkSecuritySafetySourceTest.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.content.Intent;
import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
import android.util.Singleton;
import com.android.internal.R;
@@ -50,6 +51,7 @@
import org.mockito.ArgumentCaptor;
import java.time.Instant;
+import java.util.List;
public final class CellularNetworkSecuritySafetySourceTest extends TelephonyTest {
@@ -76,13 +78,19 @@
mContextFixture.putResource(R.string.scCellularNetworkSecurityTitle, "fake");
mContextFixture.putResource(R.string.scCellularNetworkSecuritySummary, "fake");
- mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedTitle, "fake %1$s");
- mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedSummary, "fake");
+ mContextFixture.putResource(R.string.scCellularNetworkSecurityLearnMore,
+ "https://support.google.com/android?p=cellular_security");
+ mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedTitle, "fake");
+ mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedSummary, "fake %1$s");
+ mContextFixture.putResource(R.string.scNullCipherIssueNonEncryptedSummaryNotification,
+ "fake %1$s");
mContextFixture.putResource(R.string.scNullCipherIssueEncryptedTitle, "fake %1$s");
- mContextFixture.putResource(R.string.scNullCipherIssueEncryptedSummary, "fake");
+ mContextFixture.putResource(R.string.scNullCipherIssueEncryptedSummary, "fake %1$s");
mContextFixture.putResource(R.string.scIdentifierDisclosureIssueTitle, "fake");
+ mContextFixture.putResource(R.string.scIdentifierDisclosureIssueSummaryNotification,
+ "fake %1$s %2$s");
mContextFixture.putResource(
- R.string.scIdentifierDisclosureIssueSummary, "fake %1$d %2$tr %3$tr %4$s");
+ R.string.scIdentifierDisclosureIssueSummary, "fake %1$s %2$s");
mContextFixture.putResource(R.string.scNullCipherIssueActionSettings, "fake");
mContextFixture.putResource(R.string.scNullCipherIssueActionLearnMore, "fake");
@@ -172,6 +180,26 @@
}
@Test
+ public void clearNullCipherState() {
+ ArgumentCaptor<SafetySourceData> data = ArgumentCaptor.forClass(SafetySourceData.class);
+
+ mSafetySource.setNullCipherIssueEnabled(mContext, true);
+ mSafetySource.setNullCipherState(mContext, 0, NULL_CIPHER_STATE_NOTIFY_ENCRYPTED);
+ mSafetySource.clearNullCipherState(mContext, 0);
+
+ // Once for enable, once for encrypted state, and once for clearing state
+ verify(mSafetyCenterManagerWrapper, times(3)).setSafetySourceData(data.capture());
+
+ // initial check that our encrypted state update created an issue
+ assertThat(data.getAllValues().get(1).getStatus()).isNotNull();
+ assertThat(data.getAllValues().get(1).getIssues()).hasSize(1);
+
+ // assert that our last call to clear state results in no issues sent to SC
+ assertThat(data.getAllValues().get(2).getStatus()).isNotNull();
+ assertThat(data.getAllValues().get(2).getIssues()).isEmpty();
+ }
+
+ @Test
public void disableIdentifierDisclosueIssue_nullData() {
// We must first enable before disabling, since a standalone call to disable may result in
// a no-op when the default for a new notifier is to be disabled.
@@ -245,4 +273,24 @@
assertThat(data.getAllValues().get(3).getStatus()).isNotNull();
assertThat(data.getAllValues().get(3).getIssues()).hasSize(2);
}
+
+ @Test
+ public void learnMoreLinkEmpty_learnMoreIsHidden() {
+ mContextFixture.putResource(R.string.scCellularNetworkSecurityLearnMore, "");
+
+ ArgumentCaptor<SafetySourceData> data = ArgumentCaptor.forClass(SafetySourceData.class);
+
+ mSafetySource.setNullCipherIssueEnabled(mContext, true);
+ mSafetySource.setNullCipherState(mContext, 0, NULL_CIPHER_STATE_NOTIFY_NON_ENCRYPTED);
+ mSafetySource.setIdentifierDisclosureIssueEnabled(mContext, true);
+ mSafetySource.setIdentifierDisclosure(mContext, 0, 12, Instant.now(), Instant.now());
+
+ verify(mSafetyCenterManagerWrapper, times(4)).setSafetySourceData(data.capture());
+ List<SafetySourceIssue.Action> actions = data.getAllValues().get(
+ 3).getIssues().getFirst().getActions();
+
+ // we only see the action that takes you to the settings page
+ assertThat(actions).hasSize(1);
+ assertThat(actions.getFirst().getId()).isEqualTo("cellular_security_settings");
+ }
}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
index 0bb7b76..6a4d2fb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/security/NullCipherNotifierTest.java
@@ -45,6 +45,7 @@
public class NullCipherNotifierTest {
private static final int SUB_ID = 3425;
+ private static final int PHONE_ID = 999;
private static final List<Integer> NON_TRANSPORT_LAYER_EVENTS =
List.of(SecurityAlgorithmUpdate.CONNECTION_EVENT_VOLTE_SIP,
SecurityAlgorithmUpdate.CONNECTION_EVENT_VOLTE_SIP_SOS,
@@ -149,9 +150,11 @@
@Test
public void onSecurityAlgorithmUpdate_enabled_unprotectedEmergency_noSafetySourceUpdate() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
@@ -163,6 +166,24 @@
}
@Test
+ public void onSecurityAlgorithmUpdate_disabled_noSafetySourceUpdate() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.disable(mContext);
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ new SecurityAlgorithmUpdate(
+ SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_HMAC_SHA1_96,
+ /* isUnprotectedEmergency= */ false));
+
+ verify(mSafetySource, never()).setNullCipherState(any(), anyInt(), anyInt());
+ }
+
+ @Test
public void onSecurityAlgorithmUpdate_enabled_nonTransportLayerEvent_noSafetySourceUpdate() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
@@ -170,6 +191,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -185,12 +207,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNullCipher_notifyNonEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -214,12 +238,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_integrityNullCipher_notifyNonEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int integrityAlgorithm : NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -243,12 +269,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNonNullCipher_encrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NON_NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -272,12 +300,14 @@
@Test
public void onUpdate_enabled_transportLayerEvent_integrityNonNullCipher_encrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int integrityAlgorithm : NON_NULL_CIPHERS) {
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -301,11 +331,13 @@
@Test
public void onUpdate_enabled_transportLayerEvent_encryptionNonNullCipher_notifyEncrypted() {
NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
for (int connectionEvent : TRANSPORT_LAYER_EVENTS) {
for (int encryptionAlgorithm : NON_NULL_CIPHERS) {
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -316,6 +348,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -345,6 +378,7 @@
for (int integrityAlgorithm : NON_NULL_CIPHERS) {
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -355,6 +389,7 @@
clearInvocations(mSafetySource);
notifier.onSecurityAlgorithmUpdate(
mContext,
+ PHONE_ID,
SUB_ID,
new SecurityAlgorithmUpdate(
connectionEvent,
@@ -374,4 +409,88 @@
}
}
}
+
+ @Test
+ public void onSecurityAlgorithmUpdate_updateSubscriptionId_clearsOldId() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
+
+ int connectionEvent = SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G;
+ int encryptionAlgorithm = SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2;
+ int subId2 = 1337;
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ getWellEncryptedUpdate());
+
+ notifier.setSubscriptionMapping(mContext, PHONE_ID, subId2);
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(SUB_ID),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ verify(mSafetySource, times(1)).clearNullCipherState(eq(mContext), eq(SUB_ID));
+ }
+
+ @Test
+ public void onSecurityAlgorithmUpdate_newSubIdOnAlgoUpdate_clearsOldId() {
+ NullCipherNotifier notifier = new NullCipherNotifier(mExecutor, mSafetySource);
+ notifier.enable(mContext);
+
+ int connectionEvent = SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G;
+ int encryptionAlgorithm = SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2;
+ int subId2 = 1337;
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ SUB_ID,
+ getWellEncryptedUpdate());
+
+ notifier.onSecurityAlgorithmUpdate(
+ mContext,
+ PHONE_ID,
+ subId2,
+ getWellEncryptedUpdate());
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "SubId: " + SUB_ID + "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(SUB_ID),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ // The update with subId2 should clear subId1 data since they have the same phone id
+ verify(mSafetySource, times(1)).clearNullCipherState(eq(mContext), eq(SUB_ID));
+
+ verify(
+ mSafetySource,
+ times(1).description(
+ "SubId: " + SUB_ID + "Connection event: " + connectionEvent
+ + " Encryption algorithm: " + encryptionAlgorithm))
+ .setNullCipherState(
+ eq(mContext),
+ eq(subId2),
+ eq(NULL_CIPHER_STATE_ENCRYPTED));
+
+ }
+
+ private SecurityAlgorithmUpdate getWellEncryptedUpdate() {
+ return new SecurityAlgorithmUpdate(
+ SecurityAlgorithmUpdate.CONNECTION_EVENT_AS_SIGNALLING_5G,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_EEA2,
+ SecurityAlgorithmUpdate.SECURITY_ALGORITHM_HMAC_SHA1_96,
+ /* isUnprotectedEmergency= */ false);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
index 7339e42..62b9def 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java
@@ -76,8 +76,8 @@
static final String FAKE_DEFAULT_CARD_NAME = "CARD %d";
static final String FAKE_ICCID1 = "123456";
static final String FAKE_ICCID2 = "456789";
- static final String FAKE_PHONE_NUMBER1 = "6502530000";
- static final String FAKE_PHONE_NUMBER2 = "4089961010";
+ static final String FAKE_PHONE_NUMBER1 = "9995551234";
+ static final String FAKE_PHONE_NUMBER2 = "9998887777";
static final String FAKE_CARRIER_NAME1 = "A-Mobile";
static final String FAKE_CARRIER_NAME2 = "B-Mobile";
static final int FAKE_COLOR1 = 1;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index 9fee311..eb06ff1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -44,6 +44,7 @@
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG1;
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG2;
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_ENTITLEMENT_PLMNS1;
+import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_DISABLED;
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO1;
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO2;
import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_UUID1;
@@ -243,7 +244,6 @@
doReturn(false).when(mFlags).enforceTelephonyFeatureMappingForPublicApis();
doReturn(true).when(mPackageManager).hasSystemFeature(
eq(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
-
logd("SubscriptionManagerServiceTest -Setup!");
}
@@ -426,21 +426,35 @@
@Test
public void testSetAdminOwned() {
mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
- mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1,
- 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
+ mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0,
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
processAllMessages();
String groupOwner = "test";
mSubscriptionManagerServiceUT.setGroupOwner(1, groupOwner);
- SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
- .getSubscriptionInfoInternal(1);
+ SubscriptionInfoInternal subInfo =
+ mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1);
assertThat(subInfo).isNotNull();
assertThat(subInfo.getGroupOwner()).isEqualTo(groupOwner);
verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1));
}
@Test
+ public void testSetGroupOwner_callerMissingpPermission_throws() {
+ mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+ mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0,
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
+ processAllMessages();
+ String groupOwner = "test";
+ // Remove MODIFY_PHONE_STATE
+ mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+
+ assertThrows(SecurityException.class,
+ () -> mSubscriptionManagerServiceUT.setGroupOwner(1, groupOwner));
+ }
+
+ @Test
@DisableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
public void testSetPhoneNumber() {
doReturn(false).when(mFlags).enforceTelephonyFeatureMapping();
@@ -484,7 +498,8 @@
@Test
@EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING})
- public void testSetPhoneNumber_EnabledEnforceTelephonyFeatureMappingForPublicApis() {
+ public void testSetPhoneNumber_EnabledEnforceTelephonyFeatureMappingForPublicApis()
+ throws Exception {
mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1,
0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
@@ -496,6 +511,11 @@
// Grant carrier privilege
setCarrierPrivilegesForSubId(true, 1);
+ // Replace field to set SDK version of vendor partition to Android V
+ int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM;
+ replaceInstance(SubscriptionManagerService.class, "mVendorApiLevel",
+ mSubscriptionManagerServiceUT, vendorApiLevel);
+
// Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined
doReturn(true).when(mFlags).enforceTelephonyFeatureMappingForPublicApis();
doReturn(true).when(mPackageManager).hasSystemFeature(
@@ -1788,6 +1808,45 @@
}
@Test
+ public void testGetPhoneNumberSourcePriority() throws Exception {
+ mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_NUMBERS);
+
+ String phoneNumberFromCarrier = "8675309";
+ String phoneNumberFromUicc = "1112223333";
+ String phoneNumberFromIms = "5553466";
+ String phoneNumberFromPhoneObject = "8001234567";
+
+ doReturn(phoneNumberFromPhoneObject).when(mPhone).getLine1Number();
+
+ SubscriptionInfoInternal multiNumberSubInfo =
+ new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO1)
+ .setNumberFromCarrier(phoneNumberFromCarrier)
+ .setNumber(phoneNumberFromUicc)
+ .setNumberFromIms(phoneNumberFromIms)
+ .build();
+ int subId = insertSubscription(multiNumberSubInfo);
+
+ assertThat(mSubscriptionManagerServiceUT.getPhoneNumberFromFirstAvailableSource(
+ subId, CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(phoneNumberFromCarrier);
+
+ multiNumberSubInfo =
+ new SubscriptionInfoInternal.Builder(multiNumberSubInfo)
+ .setNumberFromCarrier("")
+ .setNumber(phoneNumberFromUicc)
+ .setNumberFromIms(phoneNumberFromIms)
+ .build();
+ subId = insertSubscription(multiNumberSubInfo);
+
+ assertThat(mSubscriptionManagerServiceUT.getPhoneNumberFromFirstAvailableSource(
+ subId, CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(phoneNumberFromPhoneObject);
+
+ doReturn("").when(mPhone).getLine1Number();
+
+ assertThat(mSubscriptionManagerServiceUT.getPhoneNumberFromFirstAvailableSource(
+ subId, CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(phoneNumberFromIms);
+ }
+
+ @Test
public void testSetUiccApplicationsEnabled() {
insertSubscription(FAKE_SUBSCRIPTION_INFO1);
@@ -2483,6 +2542,39 @@
}
@Test
+ public void testGetPhoneNumberFromDefaultSubscription() {
+ doReturn(true).when(mFlags).saferGetPhoneNumber();
+
+ mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
+ mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+ int subId = insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+
+ mSubscriptionManagerServiceUT.setDefaultVoiceSubId(subId);
+
+ assertThat(
+ mSubscriptionManagerServiceUT.getPhoneNumberFromFirstAvailableSource(
+ subId, CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(FAKE_PHONE_NUMBER1);
+ assertThat(
+ mSubscriptionManagerServiceUT.getPhoneNumber(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_UICC,
+ CALLING_PACKAGE,
+ CALLING_FEATURE)).isEqualTo(FAKE_PHONE_NUMBER1);
+ assertThat(
+ mSubscriptionManagerServiceUT.getPhoneNumber(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER,
+ CALLING_PACKAGE,
+ CALLING_FEATURE)).isEqualTo(FAKE_PHONE_NUMBER1);
+ assertThat(
+ mSubscriptionManagerServiceUT.getPhoneNumber(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ SubscriptionManager.PHONE_NUMBER_SOURCE_IMS,
+ CALLING_PACKAGE,
+ CALLING_FEATURE)).isEqualTo(FAKE_PHONE_NUMBER1);
+ }
+
+ @Test
public void testEsimActivation() {
mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
@@ -3134,6 +3226,69 @@
}
@Test
+ public void testIsSatelliteSpnWithEmptySpn() {
+ mContextFixture.putResource(R.string.config_satellite_sim_spn_identifier, ""); // Empty
+ System.setProperty("persist.radio.allow_mock_modem", "true");
+ doReturn(true).when(mFlags).oemEnabledSatelliteFlag();
+
+ EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1)
+ .setIccid(FAKE_ICCID1)
+ .setNickname(FAKE_CARRIER_NAME1)
+ .setServiceProviderName(FAKE_CARRIER_NAME1)
+ .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+ .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC1, FAKE_MNC1,
+ FAKE_CARRIER_NAME1, null, null, null, FAKE_CARRIER_ID1, FAKE_CARRIER_ID1))
+ .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules(
+ FAKE_NATIVE_ACCESS_RULES1)))
+ .build();
+
+ GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult(
+ EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false);
+ doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1));
+ doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot)
+ .getPortIndexFromIccId(anyString());
+ doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1));
+
+ mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null);
+ processAllMessages();
+
+ SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
+ .getSubscriptionInfoInternal(1);
+ assertThat(subInfo.getOnlyNonTerrestrialNetwork())
+ .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED);
+
+ mContextFixture.putResource(R.string.config_satellite_sim_spn_identifier,
+ FAKE_CARRIER_NAME1);
+ EuiccProfileInfo profileInfo2 = new EuiccProfileInfo.Builder(FAKE_ICCID2)
+ .setIccid(FAKE_ICCID2)
+ .setNickname(FAKE_CARRIER_NAME2)
+ .setServiceProviderName("")
+ .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+ .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2,
+ FAKE_CARRIER_NAME2, null, null, null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2))
+ .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules(
+ FAKE_NATIVE_ACCESS_RULES2)))
+ .build();
+ result = new GetEuiccProfileInfoListResult(
+ EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo2}, false);
+ doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(2));
+ doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot)
+ .getPortIndexFromIccId(anyString());
+ doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2));
+
+ mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(2), null);
+ processAllMessages();
+
+ subInfo = mSubscriptionManagerServiceUT
+ .getSubscriptionInfoInternal(2);
+ assertThat(subInfo.getOnlyNonTerrestrialNetwork())
+ .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED);
+
+ System.setProperty("persist.radio.allow_mock_modem", "false");
+ doReturn(false).when(mFlags).oemEnabledSatelliteFlag();
+ }
+
+ @Test
public void testIsSatelliteSpnWithNullCarrierIdentifier() {
mContextFixture.putResource(R.string.config_satellite_sim_spn_identifier,
FAKE_CARRIER_NAME1);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java
index 1a846c4..5c1993f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java
@@ -20,11 +20,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.os.Binder;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -33,9 +38,11 @@
import com.android.internal.telephony.IccLogicalChannelRequest;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.flags.Flags;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,9 +61,13 @@
private int mPhoneId = 0;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
+ mSetFlagsRule.enableFlags(Flags.FLAG_CLEANUP_OPEN_LOGICAL_CHANNEL_RECORD_ON_DISPOSE);
mUiccCard = mock(UiccCard.class);
mIccCardStatus = mock(IccCardStatus.class);
/* initially there are no application available */
@@ -144,6 +155,20 @@
verify(mUiccProfile).iccCloseLogicalChannel(eq(CHANNEL_ID), eq(false), eq(null));
}
+ @Test
+ @SmallTest
+ public void testOnOpenLogicalChannel_withPortDisposed_noRecordLeft() {
+ IccLogicalChannelRequest request = getIccLogicalChannelRequest();
+
+ mUiccPort.onLogicalChannelOpened(request);
+ mUiccPort.dispose();
+
+ UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord(
+ CHANNEL_ID);
+ assertThat(record).isNull();
+ verify(mUiccProfile, never()).iccCloseLogicalChannel(anyInt(), anyBoolean(), any());
+ }
+
private IccLogicalChannelRequest getIccLogicalChannelRequest() {
IccLogicalChannelRequest request = new IccLogicalChannelRequest();
request.channel = CHANNEL_ID;